Add support for ELF shared libraries. Loosely based on work by

Eric Youngdale <ericy@cais.com>.
	* libelf.h (struct elf_backend_data): Add new fields for dynamic
	linking: elf_backend_create_dynamic_sections,
	elf_backend_adjust_dynamic_symbol,
	elf_backend_size_dynamic_sections,
	elf_backend_finish_dynamic_symbol,
	elf_backend_finish_dynamic_sections.
	(struct elf_link_hash_entry): Change type of align field to
	bfd_size_type.  Add fields dynindx, dynstr_index, weakdef,
	elf_link_hash_flags.
	(struct elf_link_hash_table): Add fields dynobj, dynsymcount,
	dynstr, bucketcount.
	(bfd_elf32_swap_reloc_in, bfd_elf32_swap_reloc_out): Declare.
	(bfd_elf32_swap_reloca_in, bfd_elf32_swap_reloca_out): Declare.
	(bfd_elf32_swap_dyn_in, bfd_elf32_swap_dyn_out): Declare.
	(bfd_elf32_add_dynamic_entry): Declare.
	(bfd_elf64_swap_reloc_in, bfd_elf64_swap_reloc_out): Declare.
	(bfd_elf64_swap_reloca_in, bfd_elf64_swap_reloca_out): Declare.
	(bfd_elf64_swap_dyn_in, bfd_elf64_swap_dyn_out): Declare.
	(bfd_elf64_add_dynamic_entry): Declare.
	* elfcode.h (Elf_External_Dyn): Define.
	(elf_swap_reloc_in): Define as macro using NAME.  Make externally
	visible.
	(elf_swap_reloc_out): Likewise.
	(elf_swap_reloca_in, elf_swap_reloca_out): Likewise.
	(elf_swap_dyn_in, elf_swap_dyn_out): Define as macro using NAME
	and as new externally visible function.
	(elf_fake_sections): Set section type of dynamic sections based on
	section names.
	(elf_write_phdrs): Remove.
	(assign_file_position_for_section): Add new align argument.
	Change all callers.
	(get_program_header_size): New static function.
	(struct seg_info): Remove.
	(map_program_segments): Completely rewrite.
	(assign_file_positions_except_relocs): Completely rewrite.
	(assign_file_positions_for_relocs): Don't set a file position for
	sections which already have one.  Don't bother to align the file
	position here.
	(section_from_elf_index): Handle SHT_HASH and SHT_DYNAMIC
	section types.
	(elf_section_from_bfd_section): Likewise.
	(elf_slurp_symbol_table): If section_from_elf_index fails, just
	use bfd_abs_section rather than returning an error.
	(elf_sizeof_headers): Make useful.
	(elf_link_record_dynamic_symbol): New static function.
	(elf_link_add_object_symbols): Handle dynamic objects.
	(elf_link_create_dynamic_sections): New static function.
	(elf_add_dynamic_entry): Define as macro using NAME and as new
	externally visible function.
	(NAME(bfd_elf,record_link_assignment)): New function.
	(elf_buckets): New static variable.
	(NAME(bfd_elf,size_dynamic_sections)): New function.
	(struct elf_final_link_info): Add dynsym_sec and hash_sec fields.
	(elf_bfd_final_link): Handle dynamic linking.  Create a section
	symbol for all ELF sections, not all BFD sections.  Store section
	symbol index in target_index field, not index field.  Traverse
	over global symbols even if stripping.
	(elf_link_output_extsym): Output dynamic symbols.  Mark symbols
	defined by dynamic objects as undefined.
	(elf_link_input_bfd): Ignore dynamic objects.  Use target_index
	field for section relocs, and make sure it is set.
	(elf_reloc_link_order): Use target_index field for section relocs,
	and make sure it is set.
	* elf.c (elf_link_hash_newfunc): Initialize dynindx, dynstr_index,
	weakdef and elf_link_hash_flags fields.
	(_bfd_elf_link_hash_table_create): Initialize dynobj, dynsymcount,
	dynstr and bucketcount fields.
	* elf32-target.h: Initialize new dynamic linking fields.
	* elf64-target.h: Likewise.
	* elf32-i386.c: New functions for dynamic linking support.
	* elf32-sparc.c: Likewise.
	* bfd-in.h (bfd_elf32_record_link_assignment): Declare.
	(bfd_elf64_record_link_assignment): Declare.
	(bfd_elf32_size_dynamic_sections): Declare.
	(bfd_elf64_size_dynamic_sections): Declare.
	* bfd-in2.h: Rebuilt.
This commit is contained in:
Ian Lance Taylor
1994-05-19 18:23:40 +00:00
parent 4be9e22a91
commit 013dec1ad9
10 changed files with 3385 additions and 501 deletions

View File

@@ -1,3 +1,84 @@
Thu May 19 11:37:11 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
Add support for ELF shared libraries. Loosely based on work by
Eric Youngdale <ericy@cais.com>.
* libelf.h (struct elf_backend_data): Add new fields for dynamic
linking: elf_backend_create_dynamic_sections,
elf_backend_adjust_dynamic_symbol,
elf_backend_size_dynamic_sections,
elf_backend_finish_dynamic_symbol,
elf_backend_finish_dynamic_sections.
(struct elf_link_hash_entry): Change type of align field to
bfd_size_type. Add fields dynindx, dynstr_index, weakdef,
elf_link_hash_flags.
(struct elf_link_hash_table): Add fields dynobj, dynsymcount,
dynstr, bucketcount.
(bfd_elf32_swap_reloc_in, bfd_elf32_swap_reloc_out): Declare.
(bfd_elf32_swap_reloca_in, bfd_elf32_swap_reloca_out): Declare.
(bfd_elf32_swap_dyn_in, bfd_elf32_swap_dyn_out): Declare.
(bfd_elf32_add_dynamic_entry): Declare.
(bfd_elf64_swap_reloc_in, bfd_elf64_swap_reloc_out): Declare.
(bfd_elf64_swap_reloca_in, bfd_elf64_swap_reloca_out): Declare.
(bfd_elf64_swap_dyn_in, bfd_elf64_swap_dyn_out): Declare.
(bfd_elf64_add_dynamic_entry): Declare.
* elfcode.h (Elf_External_Dyn): Define.
(elf_swap_reloc_in): Define as macro using NAME. Make externally
visible.
(elf_swap_reloc_out): Likewise.
(elf_swap_reloca_in, elf_swap_reloca_out): Likewise.
(elf_swap_dyn_in, elf_swap_dyn_out): Define as macro using NAME
and as new externally visible function.
(elf_fake_sections): Set section type of dynamic sections based on
section names.
(elf_write_phdrs): Remove.
(assign_file_position_for_section): Add new align argument.
Change all callers.
(get_program_header_size): New static function.
(struct seg_info): Remove.
(map_program_segments): Completely rewrite.
(assign_file_positions_except_relocs): Completely rewrite.
(assign_file_positions_for_relocs): Don't set a file position for
sections which already have one. Don't bother to align the file
position here.
(section_from_elf_index): Handle SHT_HASH and SHT_DYNAMIC
section types.
(elf_section_from_bfd_section): Likewise.
(elf_slurp_symbol_table): If section_from_elf_index fails, just
use bfd_abs_section rather than returning an error.
(elf_sizeof_headers): Make useful.
(elf_link_record_dynamic_symbol): New static function.
(elf_link_add_object_symbols): Handle dynamic objects.
(elf_link_create_dynamic_sections): New static function.
(elf_add_dynamic_entry): Define as macro using NAME and as new
externally visible function.
(NAME(bfd_elf,record_link_assignment)): New function.
(elf_buckets): New static variable.
(NAME(bfd_elf,size_dynamic_sections)): New function.
(struct elf_final_link_info): Add dynsym_sec and hash_sec fields.
(elf_bfd_final_link): Handle dynamic linking. Create a section
symbol for all ELF sections, not all BFD sections. Store section
symbol index in target_index field, not index field. Traverse
over global symbols even if stripping.
(elf_link_output_extsym): Output dynamic symbols. Mark symbols
defined by dynamic objects as undefined.
(elf_link_input_bfd): Ignore dynamic objects. Use target_index
field for section relocs, and make sure it is set.
(elf_reloc_link_order): Use target_index field for section relocs,
and make sure it is set.
* elf.c (elf_link_hash_newfunc): Initialize dynindx, dynstr_index,
weakdef and elf_link_hash_flags fields.
(_bfd_elf_link_hash_table_create): Initialize dynobj, dynsymcount,
dynstr and bucketcount fields.
* elf32-target.h: Initialize new dynamic linking fields.
* elf64-target.h: Likewise.
* elf32-i386.c: New functions for dynamic linking support.
* elf32-sparc.c: Likewise.
* bfd-in.h (bfd_elf32_record_link_assignment): Declare.
(bfd_elf64_record_link_assignment): Declare.
(bfd_elf32_size_dynamic_sections): Declare.
(bfd_elf64_size_dynamic_sections): Declare.
* bfd-in2.h: Rebuilt.
Wed May 18 08:29:04 1994 Ian Lance Taylor (ian@cygnus.com)
* som.c: Don't include <sys/dir.h> or <sys/user.h>.

View File

@@ -463,8 +463,9 @@ void bfd_putb32 PARAMS ((bfd_vma, unsigned char *));
void bfd_putl32 PARAMS ((bfd_vma, unsigned char *));
void bfd_putb16 PARAMS ((bfd_vma, unsigned char *));
void bfd_putl16 PARAMS ((bfd_vma, unsigned char *));
/* Externally visible ECOFF routines. */
/* ECOFF linking routines. */
#if defined(__STDC__) || defined(ALMOST_STDC)
struct ecoff_debug_info;
struct ecoff_debug_swap;
@@ -472,6 +473,11 @@ struct ecoff_extr;
struct symbol_cache_entry;
struct bfd_link_info;
#endif
extern bfd_vma bfd_ecoff_get_gp_value PARAMS ((bfd * abfd));
extern boolean bfd_ecoff_set_gp_value PARAMS ((bfd *abfd, bfd_vma gp_value));
extern boolean bfd_ecoff_set_regmasks
PARAMS ((bfd *abfd, unsigned long gprmask, unsigned long fprmask,
unsigned long *cprmask));
extern PTR bfd_ecoff_debug_init
PARAMS ((bfd *output_bfd, struct ecoff_debug_info *output_debug,
const struct ecoff_debug_swap *output_swap,
@@ -513,4 +519,15 @@ extern boolean bfd_ecoff_write_accumulated_debug
const struct ecoff_debug_swap *swap,
struct bfd_link_info *info, file_ptr where));
/* Externally visible ELF routines. */
extern boolean bfd_elf32_record_link_assignment
PARAMS ((bfd *, struct bfd_link_info *, const char *));
extern boolean bfd_elf64_record_link_assignment
PARAMS ((bfd *, struct bfd_link_info *, const char *));
extern boolean bfd_elf32_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
extern boolean bfd_elf64_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
/* And more from the source. */

View File

@@ -519,6 +519,17 @@ extern boolean bfd_ecoff_write_accumulated_debug
const struct ecoff_debug_swap *swap,
struct bfd_link_info *info, file_ptr where));
/* Externally visible ELF routines. */
extern boolean bfd_elf32_record_link_assignment
PARAMS ((bfd *, struct bfd_link_info *, const char *));
extern boolean bfd_elf64_record_link_assignment
PARAMS ((bfd *, struct bfd_link_info *, const char *));
extern boolean bfd_elf32_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
extern boolean bfd_elf64_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
/* And more from the source. */
void
bfd_init PARAMS ((void));

125
bfd/elf.c
View File

@@ -33,6 +33,7 @@ SECTION
#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#define ARCH_SIZE 0
#include "libelf.h"
@@ -41,8 +42,8 @@ SECTION
cause invalid hash tables to be generated. (Well, you would if this
were being used yet.) */
unsigned long
DEFUN (bfd_elf_hash, (name),
CONST unsigned char *name)
bfd_elf_hash (name)
CONST unsigned char *name;
{
unsigned long h = 0;
unsigned long g;
@@ -65,33 +66,32 @@ DEFUN (bfd_elf_hash, (name),
buffer. */
static char *
DEFUN (elf_read, (abfd, offset, size),
bfd * abfd AND
long offset AND
int size)
elf_read (abfd, offset, size)
bfd * abfd;
long offset;
int size;
{
char *buf;
if ((buf = bfd_alloc (abfd, size)) == NULL)
{
bfd_error = no_memory;
bfd_set_error (bfd_error_no_memory);
return NULL;
}
if (bfd_seek (abfd, offset, SEEK_SET) == -1)
{
bfd_error = system_call_error;
return NULL;
}
return NULL;
if (bfd_read ((PTR) buf, size, 1, abfd) != size)
{
bfd_error = system_call_error;
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_file_truncated);
return NULL;
}
return buf;
}
boolean
DEFUN (elf_mkobject, (abfd), bfd * abfd)
elf_mkobject (abfd)
bfd * abfd;
{
/* this just does initialization */
/* coff_mkobject zalloc's space for tdata.coff_obj_data ... */
@@ -99,7 +99,7 @@ DEFUN (elf_mkobject, (abfd), bfd * abfd)
bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
if (elf_tdata (abfd) == 0)
{
bfd_error = no_memory;
bfd_set_error (bfd_error_no_memory);
return false;
}
/* since everything is done at close time, do we need any
@@ -109,9 +109,9 @@ DEFUN (elf_mkobject, (abfd), bfd * abfd)
}
char *
DEFUN (elf_get_str_section, (abfd, shindex),
bfd * abfd AND
unsigned int shindex)
elf_get_str_section (abfd, shindex)
bfd * abfd;
unsigned int shindex;
{
Elf_Internal_Shdr **i_shdrp;
char *shstrtab = NULL;
@@ -135,10 +135,10 @@ DEFUN (elf_get_str_section, (abfd, shindex),
}
char *
DEFUN (elf_string_from_elf_section, (abfd, shindex, strindex),
bfd * abfd AND
unsigned int shindex AND
unsigned int strindex)
elf_string_from_elf_section (abfd, shindex, strindex)
bfd * abfd;
unsigned int shindex;
unsigned int strindex;
{
Elf_Internal_Shdr *hdr;
@@ -170,9 +170,9 @@ DESCRIPTION
*/
struct elf_internal_shdr *
DEFUN (bfd_elf_find_section, (abfd, name),
bfd * abfd AND
char *name)
bfd_elf_find_section (abfd, name)
bfd * abfd;
char *name;
{
Elf_Internal_Shdr **i_shdrp;
char *shstrtab;
@@ -210,6 +210,7 @@ const char *const bfd_elf_section_type_names[] = {
function. It just short circuits the reloc if producing
relocateable output against an external symbol. */
/*ARGSUSED*/
bfd_reloc_status_type
bfd_elf_generic_reloc (abfd,
reloc_entry,
@@ -237,3 +238,79 @@ bfd_elf_generic_reloc (abfd,
return bfd_reloc_continue;
}
/* Generic ELF link code. */
static struct bfd_hash_entry *elf_link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
/* Create an entry in an ELF linker hash table. */
static struct bfd_hash_entry *
elf_link_hash_newfunc (entry, table, string)
struct bfd_hash_entry *entry;
struct bfd_hash_table *table;
const char *string;
{
struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry;
/* Allocate the structure if it has not already been allocated by a
subclass. */
if (ret == (struct elf_link_hash_entry *) NULL)
ret = ((struct elf_link_hash_entry *)
bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)));
if (ret == (struct elf_link_hash_entry *) NULL)
{
bfd_set_error (bfd_error_no_memory);
return (struct bfd_hash_entry *) ret;
}
/* Call the allocation method of the superclass. */
ret = ((struct elf_link_hash_entry *)
_bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
if (ret != (struct elf_link_hash_entry *) NULL)
{
/* Set local fields. */
ret->indx = -1;
ret->size = 0;
ret->align = 0;
ret->dynindx = -1;
ret->dynstr_index = 0;
ret->weakdef = NULL;
ret->type = STT_NOTYPE;
ret->elf_link_hash_flags = 0;
}
return (struct bfd_hash_entry *) ret;
}
/* Create an ELF linker hash table. */
struct bfd_link_hash_table *
_bfd_elf_link_hash_table_create (abfd)
bfd *abfd;
{
struct elf_link_hash_table *ret;
ret = ((struct elf_link_hash_table *)
bfd_alloc (abfd, sizeof (struct elf_link_hash_table)));
if (ret == (struct elf_link_hash_table *) NULL)
{
bfd_set_error (bfd_error_no_memory);
return NULL;
}
if (! _bfd_link_hash_table_init (&ret->root, abfd,
elf_link_hash_newfunc))
{
bfd_release (abfd, ret);
return NULL;
}
ret->dynobj = NULL;
ret->dynsymcount = 0;
ret->dynstr = NULL;
ret->bucketcount = 0;
return &ret->root;
}

View File

@@ -19,9 +19,33 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "libelf.h"
static CONST struct reloc_howto_struct *elf_i386_reloc_type_lookup
PARAMS ((bfd *, bfd_reloc_code_real_type));
static void elf_i386_info_to_howto
PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
static void elf_i386_info_to_howto_rel
PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
static boolean elf_i386_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf_i386_adjust_dynamic_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
static boolean elf_i386_allocate_dynamic_section
PARAMS ((bfd *, const char *));
static boolean elf_i386_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf_i386_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
static boolean elf_i386_finish_dynamic_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
Elf_Internal_Sym *));
static boolean elf_i386_finish_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
#define USE_REL 1 /* 386 uses REL relocations instead of RELA */
enum reloc_type
@@ -79,9 +103,9 @@ static reloc_howto_type elf_howto_table[]=
#endif
static CONST struct reloc_howto_struct *
DEFUN (elf_i386_reloc_type_lookup, (abfd, code),
bfd *abfd AND
bfd_reloc_code_real_type code)
elf_i386_reloc_type_lookup (abfd, code)
bfd *abfd;
bfd_reloc_code_real_type code;
{
switch (code)
{
@@ -138,10 +162,10 @@ DEFUN (elf_i386_reloc_type_lookup, (abfd, code),
}
static void
DEFUN(elf_i386_info_to_howto, (abfd, cache_ptr, dst),
bfd *abfd AND
arelent *cache_ptr AND
Elf32_Internal_Rela *dst)
elf_i386_info_to_howto (abfd, cache_ptr, dst)
bfd *abfd;
arelent *cache_ptr;
Elf32_Internal_Rela *dst;
{
BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max);
@@ -149,15 +173,735 @@ DEFUN(elf_i386_info_to_howto, (abfd, cache_ptr, dst),
}
static void
DEFUN(elf_i386_info_to_howto_rel, (abfd, cache_ptr, dst),
bfd *abfd AND
arelent *cache_ptr AND
Elf32_Internal_Rel *dst)
elf_i386_info_to_howto_rel (abfd, cache_ptr, dst)
bfd *abfd;
arelent *cache_ptr;
Elf32_Internal_Rel *dst;
{
BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max);
cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)];
}
/* Functions for the i386 ELF linker. */
/* The name of the dynamic interpreter. This is put in the .interp
section. */
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1"
/* The size in bytes of an entry in the procedure linkage table. */
#define PLT_ENTRY_SIZE 16
/* The first entry in an absolute procedure linkage table looks like
this. See the SVR4 ABI i386 supplement to see how this works. */
static bfd_byte elf_i386_plt0_entry[PLT_ENTRY_SIZE] =
{
0xff, 0x35, /* pushl contents of address */
0, 0, 0, 0, /* replaced with address of .got + 4. */
0xff, 0x25, /* jmp indirect */
0, 0, 0, 0, /* replaced with address of .got + 8. */
0, 0, 0, 0 /* pad out to 16 bytes. */
};
/* Subsequent entries in an absolute procedure linkage table look like
this. */
static bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] =
{
0xff, 0x25, /* jmp indirect */
0, 0, 0, 0, /* replaced with address of this symbol in .got. */
0x68, /* pushl immediate */
0, 0, 0, 0, /* replaced with offset into relocation table. */
0xe9, /* jmp relative */
0, 0, 0, 0 /* replaced with offset to start of .plt. */
};
/* Create dynamic sections when linking against a dynamic object. */
static boolean
elf_i386_create_dynamic_sections (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
flagword flags;
register asection *s;
struct elf_link_hash_entry *h;
/* We need to create .plt, .rel.plt, .got, .dynbss, and .rel.bss
sections. */
flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
s = bfd_make_section (abfd, ".plt");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY | SEC_CODE)
|| ! bfd_set_section_alignment (abfd, s, 2))
return false;
s = bfd_make_section (abfd, ".rel.plt");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
|| ! bfd_set_section_alignment (abfd, s, 2))
return false;
s = bfd_make_section (abfd, ".got");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags)
|| ! bfd_set_section_alignment (abfd, s, 2))
return false;
/* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
section. We don't do this in the linker script because we don't
want to define the symbol if we are not creating a global offset
table. */
h = NULL;
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, (bfd_vma) 0,
(const char *) NULL, false, get_elf_backend_data (abfd)->collect,
(struct bfd_link_hash_entry **) &h)))
return false;
h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
/* The first three global offset table entries are reserved. */
s->_raw_size += 3 * 4;
/* The .dynbss section is a place to put symbols which are defined
by dynamic objects, are referenced by regular objects, and are
not functions. We must allocate space for them in the process
image and use a R_386_COPY reloc to tell the dynamic linker to
initialize them at run time. The linker script puts the .dynbss
section into the .bss section of the final image. */
s = bfd_make_section (abfd, ".dynbss");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, SEC_ALLOC))
return false;
/* The .rel.bss section holds copy relocs. This section is not
normally needed. We need to create it here, though, so that the
linker will map it to an output section. If it turns out not to
be needed, we can discard it later. */
s = bfd_make_section (abfd, ".rel.bss");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
|| ! bfd_set_section_alignment (abfd, s, 2))
return false;
return true;
}
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
change the definition to something the rest of the link can
understand. */
static boolean
elf_i386_adjust_dynamic_symbol (info, h)
struct bfd_link_info *info;
struct elf_link_hash_entry *h;
{
bfd *dynobj;
asection *s;
unsigned int power_of_two;
size_t align;
dynobj = elf_hash_table (info)->dynobj;
/* Make sure we know what is going on here. */
BFD_ASSERT (dynobj != NULL
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
&& (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
&& h->root.type == bfd_link_hash_defined
&& (bfd_get_flavour (h->root.u.def.section->owner)
== bfd_target_elf_flavour)
&& (elf_elfheader (h->root.u.def.section->owner)->e_type
== ET_DYN)
&& h->root.u.def.section->output_section == NULL);
/* If this is a function, put it in the procedure linkage table. We
will fill in the contents of the procedure linkage table later,
when we know the address of the .got section. */
if (h->type == STT_FUNC)
{
s = bfd_get_section_by_name (dynobj, ".plt");
BFD_ASSERT (s != NULL);
/* If this is the first .plt entry, make room for the special
first entry. */
if (s->_raw_size == 0)
s->_raw_size += PLT_ENTRY_SIZE;
/* Set the symbol to this location in the .plt. */
h->root.u.def.section = s;
h->root.u.def.value = s->_raw_size;
/* Make room for this entry. */
s->_raw_size += PLT_ENTRY_SIZE;
/* We also need to make an entry in the .got section. */
s = bfd_get_section_by_name (dynobj, ".got");
BFD_ASSERT (s != NULL);
s->_raw_size += 4;
/* We also need to make an entry in the .rel.plt section. */
s = bfd_get_section_by_name (dynobj, ".rel.plt");
BFD_ASSERT (s != NULL);
s->_raw_size += sizeof (Elf32_External_Rel);
return true;
}
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
if (h->weakdef != NULL)
{
BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined);
h->root.u.def.section = h->weakdef->root.u.def.section;
h->root.u.def.value = h->weakdef->root.u.def.value;
h->align = (bfd_size_type) -1;
return true;
}
/* This is a reference to a symbol defined by a dynamic object which
is not a function. We must allocate it in our .dynbss section,
which will become part of the .bss section of the executable.
There will be an entry for this symbol in the .dynsym section.
The dynamic object will contain position independent code, so all
references from the dynamic object to this symbol will go through
the global offset table. The dynamic linker will use the .dynsym
entry to determine the address it must put in the global offset
table, so both the dynamic object and the regular object will
refer to the same memory location for the variable. */
s = bfd_get_section_by_name (dynobj, ".dynbss");
BFD_ASSERT (s != NULL);
/* If the symbol is currently defined in the .bss section of the
dynamic object, then it is OK to simply initialize it to zero.
If the symbol is in some other section, we must generate a
R_386_COPY reloc to tell the dynamic linker to copy the initial
value out of the dynamic object and into the runtime process
image. We need to remember the offset into the .rel.bss section
we are going to use, and we coopt the align field for this
purpose (the align field is only used for common symbols, and
these symbols are always defined). It would be cleaner to use a
new field, but that would waste memory. */
if ((h->root.u.def.section->flags & SEC_LOAD) == 0)
h->align = (bfd_size_type) -1;
else
{
asection *srel;
srel = bfd_get_section_by_name (dynobj, ".rel.bss");
BFD_ASSERT (srel != NULL);
h->align = srel->_raw_size;
srel->_raw_size += sizeof (Elf32_External_Rel);
}
/* We need to figure out the alignment required for this symbol. I
have no idea how ELF linkers handle this. */
switch (h->size)
{
case 0:
case 1:
power_of_two = 0;
align = 1;
break;
case 2:
power_of_two = 1;
align = 2;
break;
case 3:
case 4:
power_of_two = 2;
align = 4;
break;
case 5:
case 6:
case 7:
case 8:
power_of_two = 3;
align = 8;
break;
default:
power_of_two = 4;
align = 16;
break;
}
/* Apply the required alignment. */
s->_raw_size = BFD_ALIGN (s->_raw_size, align);
if (power_of_two > bfd_get_section_alignment (dynobj, s))
{
if (! bfd_set_section_alignment (dynobj, s, power_of_two))
return false;
}
/* Define the symbol as being at this point in the section. */
h->root.u.def.section = s;
h->root.u.def.value = s->_raw_size;
/* Increment the section size to make room for the symbol. */
s->_raw_size += h->size;
return true;
}
/* Allocate contents for a section. */
static INLINE boolean
elf_i386_allocate_dynamic_section (dynobj, name)
bfd *dynobj;
const char *name;
{
register asection *s;
s = bfd_get_section_by_name (dynobj, name);
BFD_ASSERT (s != NULL);
s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
if (s->contents == NULL && s->_raw_size != 0)
{
bfd_set_error (bfd_error_no_memory);
return false;
}
return true;
}
/* Set the sizes of the dynamic sections. */
static boolean
elf_i386_size_dynamic_sections (output_bfd, info)
bfd *output_bfd;
struct bfd_link_info *info;
{
bfd *dynobj;
asection *s;
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
/* Set the contents of the .interp section to the interpreter. */
s = bfd_get_section_by_name (dynobj, ".interp");
BFD_ASSERT (s != NULL);
s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
/* The adjust_dynamic_symbol entry point has determined the sizes of
the various dynamic sections. Allocate some memory for them to
hold contents. */
if (! elf_i386_allocate_dynamic_section (dynobj, ".plt")
|| ! elf_i386_allocate_dynamic_section (dynobj, ".rel.plt")
|| ! elf_i386_allocate_dynamic_section (dynobj, ".got")
|| ! elf_i386_allocate_dynamic_section (dynobj, ".rel.bss"))
return false;
/* Add some entries to the .dynamic section. We fill in the values
later, in elf_i386_finish_dynamic_sections, but we must add the
entries now so that we get the correct size for the .dynamic
section. */
if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0))
return false;
s = bfd_get_section_by_name (dynobj, ".plt");
BFD_ASSERT (s != NULL);
if (s->_raw_size != 0)
{
if (! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_REL)
|| ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0))
return false;
}
/* If we didn't need the .rel.bss section, then discard it from the
output file. This is a hack. We don't bother to do it for the
other sections because they normally are needed. */
s = bfd_get_section_by_name (dynobj, ".rel.bss");
BFD_ASSERT (s != NULL);
if (s->_raw_size == 0)
{
asection **spp;
for (spp = &s->output_section->owner->sections;
*spp != s->output_section;
spp = &(*spp)->next)
;
*spp = s->output_section->next;
--s->output_section->owner->section_count;
}
else
{
if (! bfd_elf32_add_dynamic_entry (info, DT_REL, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_RELSZ, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_RELENT,
sizeof (Elf32_External_Rel)))
return false;
}
return true;
}
/* Relocate an i386 ELF section. */
static boolean
elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
contents, relocs, local_syms, local_sections)
bfd *output_bfd;
struct bfd_link_info *info;
bfd *input_bfd;
asection *input_section;
bfd_byte *contents;
Elf_Internal_Rela *relocs;
Elf_Internal_Sym *local_syms;
asection **local_sections;
{
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
{
int r_type;
const reloc_howto_type *howto;
long r_symndx;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
asection *sec;
bfd_vma relocation;
bfd_reloc_status_type r;
r_type = ELF32_R_TYPE (rel->r_info);
if (r_type < 0 || r_type >= (int) R_386_max)
{
bfd_set_error (bfd_error_bad_value);
return false;
}
howto = elf_howto_table + r_type;
r_symndx = ELF32_R_SYM (rel->r_info);
if (info->relocateable)
{
/* This is a relocateable link. We don't have to change
anything, unless the reloc is against a section symbol,
in which case we have to adjust according to where the
section symbol winds up in the output section. */
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
{
bfd_vma val;
sec = local_sections[r_symndx];
val = bfd_get_32 (input_bfd, contents + rel->r_offset);
val += sec->output_offset + sym->st_value;
bfd_put_32 (input_bfd, val, contents + rel->r_offset);
}
}
continue;
}
/* This is a final link. */
h = NULL;
sym = NULL;
sec = NULL;
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
relocation = (sec->output_section->vma
+ sec->output_offset
+ sym->st_value);
}
else
{
long indx;
indx = r_symndx - symtab_hdr->sh_info;
h = elf_sym_hashes (input_bfd)[indx];
if (h->root.type == bfd_link_hash_defined)
{
sec = h->root.u.def.section;
relocation = (h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
}
else if (h->root.type == bfd_link_hash_weak)
relocation = 0;
else
{
if (! ((*info->callbacks->undefined_symbol)
(info, h->root.root.string, input_bfd,
input_section, rel->r_offset)))
return false;
relocation = 0;
}
}
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, (bfd_vma) 0);
if (r != bfd_reloc_ok)
{
switch (r)
{
default:
case bfd_reloc_outofrange:
abort ();
case bfd_reloc_overflow:
{
const char *name;
if (h != NULL)
name = h->root.root.string;
else
{
name = elf_string_from_elf_section (input_bfd,
symtab_hdr->sh_link,
sym->st_name);
if (name == NULL)
return false;
if (*name == '\0')
name = bfd_section_name (input_bfd, sec);
}
if (! ((*info->callbacks->reloc_overflow)
(info, name, howto->name, (bfd_vma) 0,
input_bfd, input_section, rel->r_offset)))
return false;
}
break;
}
}
}
return true;
}
/* Finish up dynamic symbol handling. We set the contents of various
dynamic sections here. */
static boolean
elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
bfd *output_bfd;
struct bfd_link_info *info;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
{
/* If this symbol is not defined by a dynamic object, or is not
referenced by a regular object, ignore it. */
if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
|| (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
|| (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
{
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
if (strcmp (h->root.root.string, "_DYNAMIC") == 0
|| strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
sym->st_shndx = SHN_ABS;
return true;
}
BFD_ASSERT (h->root.type == bfd_link_hash_defined);
BFD_ASSERT (h->dynindx != -1);
if (h->type == STT_FUNC)
{
asection *splt;
asection *sgot;
asection *srel;
bfd_vma plt_index;
bfd_vma got_offset;
Elf_Internal_Rel rel;
splt = h->root.u.def.section;
BFD_ASSERT (strcmp (bfd_get_section_name (splt->owner, splt), ".plt")
== 0);
sgot = bfd_get_section_by_name (splt->owner, ".got");
BFD_ASSERT (sgot != NULL);
srel = bfd_get_section_by_name (splt->owner, ".rel.plt");
BFD_ASSERT (srel != NULL);
/* FIXME: This only handles an absolute procedure linkage table.
When producing a dynamic object, we need to generate a
position independent procedure linkage table. */
/* Get the index in the procedure linkage table which
corresponds to this symbol. This is the index of this symbol
in all the symbols for which we are making plt entries. The
first entry in the procedure linkage table is reserved. */
plt_index = h->root.u.def.value / PLT_ENTRY_SIZE - 1;
/* Get the offset into the .got table of the entry that
corresponds to this function. Each .got entry is 4 bytes.
The first three are reserved. */
got_offset = (plt_index + 3) * 4;
/* Fill in the entry in the procedure linkage table. */
memcpy (splt->contents + h->root.u.def.value, elf_i386_plt_entry,
PLT_ENTRY_SIZE);
bfd_put_32 (output_bfd,
(sgot->output_section->vma
+ sgot->output_offset
+ got_offset),
splt->contents + h->root.u.def.value + 2);
bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel),
splt->contents + h->root.u.def.value + 7);
bfd_put_32 (output_bfd, - (h->root.u.def.value + PLT_ENTRY_SIZE),
splt->contents + h->root.u.def.value + 12);
/* Fill in the entry in the global offset table. */
bfd_put_32 (output_bfd,
(splt->output_section->vma
+ splt->output_offset
+ h->root.u.def.value
+ 6),
sgot->contents + got_offset);
/* Fill in the entry in the .rel.plt section. */
rel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ got_offset);
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
bfd_elf32_swap_reloc_out (output_bfd, &rel,
((Elf32_External_Rel *) srel->contents
+ plt_index));
/* Mark the symbol as undefined, rather than as defined in the
.plt section. Leave the value alone. */
sym->st_shndx = SHN_UNDEF;
}
else
{
/* This is not a function. We have already allocated memory for
it in the .bss section (via .dynbss). All we have to do here
is create a COPY reloc if required. */
if (h->align != (bfd_size_type) -1)
{
asection *s;
Elf_Internal_Rel rel;
s = bfd_get_section_by_name (h->root.u.def.section->owner,
".rel.bss");
BFD_ASSERT (s != NULL);
rel.r_offset = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY);
bfd_elf32_swap_reloc_out (output_bfd, &rel,
((Elf32_External_Rel *)
(s->contents + h->align)));
}
}
return true;
}
/* Finish up the dynamic sections. */
static boolean
elf_i386_finish_dynamic_sections (output_bfd, info)
bfd *output_bfd;
struct bfd_link_info *info;
{
asection *splt;
asection *sgot;
asection *sdyn;
Elf32_External_Dyn *dyncon, *dynconend;
splt = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".plt");
sgot = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".got");
sdyn = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".dynamic");
BFD_ASSERT (splt != NULL && sgot != NULL && sdyn != NULL);
dyncon = (Elf32_External_Dyn *) sdyn->contents;
dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
for (; dyncon < dynconend; dyncon++)
{
Elf_Internal_Dyn dyn;
const char *name;
boolean size;
bfd_elf32_swap_dyn_in (elf_hash_table (info)->dynobj, dyncon, &dyn);
/* My reading of the SVR4 ABI indicates that the procedure
linkage table relocs (DT_JMPREL) should be included in the
overall relocs (DT_REL). This is what Solaris does.
However, UnixWare can not handle that case. Therefore, we
override the DT_REL and DT_RELSZ entries here to make them
not include the JMPREL relocs. */
switch (dyn.d_tag)
{
case DT_PLTGOT: name = ".got"; size = false; break;
case DT_PLTRELSZ: name = ".rel.plt"; size = true; break;
case DT_JMPREL: name = ".rel.plt"; size = false; break;
case DT_REL: name = ".rel.bss"; size = false; break;
case DT_RELSZ: name = ".rel.bss"; size = true; break;
default: name = NULL; size = false; break;
}
if (name != NULL)
{
asection *s;
s = bfd_get_section_by_name (output_bfd, name);
BFD_ASSERT (s != NULL);
if (! size)
dyn.d_un.d_ptr = s->vma;
else
{
if (s->_cooked_size != 0)
dyn.d_un.d_val = s->_cooked_size;
else
dyn.d_un.d_val = s->_raw_size;
}
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
}
}
/* Fill in the first entry in the procedure linkage table. */
if (splt->_raw_size > 0)
{
memcpy (splt->contents, elf_i386_plt0_entry, PLT_ENTRY_SIZE);
bfd_put_32 (output_bfd,
sgot->output_section->vma + sgot->output_offset + 4,
splt->contents + 2);
bfd_put_32 (output_bfd,
sgot->output_section->vma + sgot->output_offset + 8,
splt->contents + 8);
}
/* Fill in the first three entries in the global offset table. */
if (sgot->_raw_size > 0)
{
bfd_put_32 (output_bfd,
sdyn->output_section->vma + sdyn->output_offset,
sgot->contents);
bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
}
elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
/* UnixWare sets the entsize of .plt to 4, although that doesn't
really seem like the right value. */
elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
return true;
}
#define TARGET_LITTLE_SYM bfd_elf32_i386_vec
#define TARGET_LITTLE_NAME "elf32-i386"
@@ -167,5 +911,16 @@ DEFUN(elf_i386_info_to_howto_rel, (abfd, cache_ptr, dst),
#define elf_info_to_howto_rel elf_i386_info_to_howto_rel
#define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup
#define ELF_MAXPAGESIZE 0x1000
#define elf_backend_create_dynamic_sections \
elf_i386_create_dynamic_sections
#define elf_backend_adjust_dynamic_symbol \
elf_i386_adjust_dynamic_symbol
#define elf_backend_size_dynamic_sections \
elf_i386_size_dynamic_sections
#define elf_backend_relocate_section elf_i386_relocate_section
#define elf_backend_finish_dynamic_symbol \
elf_i386_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
elf_i386_finish_dynamic_sections
#include "elf32-target.h"

View File

@@ -19,9 +19,31 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "libelf.h"
static CONST struct reloc_howto_struct *bfd_elf32_bfd_reloc_type_lookup
PARAMS ((bfd *, bfd_reloc_code_real_type));
static void elf_info_to_howto
PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
static boolean elf32_sparc_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf32_sparc_adjust_dynamic_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
static boolean elf32_sparc_allocate_dynamic_section
PARAMS ((bfd *, const char *));
static boolean elf32_sparc_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf32_sparc_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
static boolean elf32_sparc_finish_dynamic_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
Elf_Internal_Sym *));
static boolean elf32_sparc_finish_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
enum reloc_type
{
R_SPARC_NONE = 0,
@@ -61,30 +83,30 @@ static CONST char *CONST reloc_type_names[] =
static reloc_howto_type elf_sparc_howto_table[] =
{
HOWTO(R_SPARC_NONE, 0,0, 0,false,0,false,false, bfd_elf_generic_reloc,"R_SPARC_NONE", false,0,0x00000000,false),
HOWTO(R_SPARC_8, 0,0, 8,false,0,true, true, bfd_elf_generic_reloc,"R_SPARC_8", false,0,0x000000ff,false),
HOWTO(R_SPARC_16, 0,1,16,false,0,true, true, bfd_elf_generic_reloc,"R_SPARC_16", false,0,0x0000ffff,false),
HOWTO(R_SPARC_32, 0,2,32,false,0,true, true, bfd_elf_generic_reloc,"R_SPARC_32", false,0,0xffffffff,false),
HOWTO(R_SPARC_DISP8, 0,0, 8,true, 0,false, true, bfd_elf_generic_reloc,"R_SPARC_DISP8", false,0,0x000000ff,false),
HOWTO(R_SPARC_DISP16, 0,1,16,true, 0,false, true, bfd_elf_generic_reloc,"R_SPARC_DISP16", false,0,0x0000ffff,false),
HOWTO(R_SPARC_DISP32, 0,2,32,true, 0,false, true, bfd_elf_generic_reloc,"R_SPARC_DISP32", false,0,0x00ffffff,false),
HOWTO(R_SPARC_WDISP30,2,2,30,true, 0,false, true, bfd_elf_generic_reloc,"R_SPARC_WDISP30",false,0,0x3fffffff,false),
HOWTO(R_SPARC_WDISP22,2,2,22,true, 0,false, true, bfd_elf_generic_reloc,"R_SPARC_WDISP22",false,0,0x003fffff,false),
HOWTO(R_SPARC_HI22, 10,2,22,false,0,true, false, bfd_elf_generic_reloc,"R_SPARC_HI22", false,0,0x003fffff,false),
HOWTO(R_SPARC_22, 0,2,22,false,0,true, true, bfd_elf_generic_reloc,"R_SPARC_22", false,0,0x003fffff,false),
HOWTO(R_SPARC_13, 0,1,13,false,0,true, true, bfd_elf_generic_reloc,"R_SPARC_13", false,0,0x00001fff,false),
HOWTO(R_SPARC_LO10, 0,1,10,false,0,true, false, bfd_elf_generic_reloc,"R_SPARC_LO10", false,0,0x000003ff,false),
HOWTO(R_SPARC_GOT10, 0,1,10,false,0,false, true, bfd_elf_generic_reloc,"R_SPARC_GOT10", false,0,0x000003ff,false),
HOWTO(R_SPARC_GOT13, 0,1,13,false,0,false, true, bfd_elf_generic_reloc,"R_SPARC_GOT13", false,0,0x00001fff,false),
HOWTO(R_SPARC_GOT22, 10,2,22,false,0,false, true, bfd_elf_generic_reloc,"R_SPARC_GOT22", false,0,0x003fffff,false),
HOWTO(R_SPARC_PC10, 0,1,10,false,0,true, true, bfd_elf_generic_reloc,"R_SPARC_PC10", false,0,0x000003ff,false),
HOWTO(R_SPARC_PC22, 0,2,22,false,0,true, true, bfd_elf_generic_reloc,"R_SPARC_PC22", false,0,0x003fffff,false),
HOWTO(R_SPARC_WPLT30, 0,0,00,false,0,false,false, bfd_elf_generic_reloc,"R_SPARC_WPLT30", false,0,0x00000000,false),
HOWTO(R_SPARC_COPY, 0,0,00,false,0,false,false, bfd_elf_generic_reloc,"R_SPARC_COPY", false,0,0x00000000,false),
HOWTO(R_SPARC_GLOB_DAT,0,0,00,false,0,false,false,bfd_elf_generic_reloc,"R_SPARC_GLOB_DAT",false,0,0x00000000,false),
HOWTO(R_SPARC_JMP_SLOT,0,0,00,false,0,false,false,bfd_elf_generic_reloc,"R_SPARC_JMP_SLOT",false,0,0x00000000,false),
HOWTO(R_SPARC_RELATIVE,0,0,00,false,0,false,false,bfd_elf_generic_reloc,"R_SPARC_RELATIVE",false,0,0x00000000,false),
HOWTO(R_SPARC_UA32, 0,0,00,false,0,false,false,bfd_elf_generic_reloc,"R_SPARC_UA32", false,0,0x00000000,false),
HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_NONE", false,0,0x00000000,true),
HOWTO(R_SPARC_8, 0,0, 8,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_8", false,0,0x000000ff,true),
HOWTO(R_SPARC_16, 0,1,16,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_16", false,0,0x0000ffff,true),
HOWTO(R_SPARC_32, 0,2,32,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_32", false,0,0xffffffff,true),
HOWTO(R_SPARC_DISP8, 0,0, 8,true, 0,complain_overflow_signed, bfd_elf_generic_reloc,"R_SPARC_DISP8", false,0,0x000000ff,true),
HOWTO(R_SPARC_DISP16, 0,1,16,true, 0,complain_overflow_signed, bfd_elf_generic_reloc,"R_SPARC_DISP16", false,0,0x0000ffff,true),
HOWTO(R_SPARC_DISP32, 0,2,32,true, 0,complain_overflow_signed, bfd_elf_generic_reloc,"R_SPARC_DISP32", false,0,0x00ffffff,true),
HOWTO(R_SPARC_WDISP30, 2,2,30,true, 0,complain_overflow_signed, bfd_elf_generic_reloc,"R_SPARC_WDISP30", false,0,0x3fffffff,true),
HOWTO(R_SPARC_WDISP22, 2,2,22,true, 0,complain_overflow_signed, bfd_elf_generic_reloc,"R_SPARC_WDISP22", false,0,0x003fffff,true),
HOWTO(R_SPARC_HI22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_HI22", false,0,0x003fffff,true),
HOWTO(R_SPARC_22, 0,2,22,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_22", false,0,0x003fffff,true),
HOWTO(R_SPARC_13, 0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_13", false,0,0x00001fff,true),
HOWTO(R_SPARC_LO10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_LO10", false,0,0x000003ff,true),
HOWTO(R_SPARC_GOT10, 0,2,10,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_GOT10", false,0,0x000003ff,true),
HOWTO(R_SPARC_GOT13, 0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_GOT13", false,0,0x00001fff,true),
HOWTO(R_SPARC_GOT22, 10,2,22,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_GOT22", false,0,0x003fffff,true),
HOWTO(R_SPARC_PC10, 0,2,10,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_PC10", false,0,0x000003ff,true),
HOWTO(R_SPARC_PC22, 0,2,22,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_PC22", false,0,0x003fffff,true),
HOWTO(R_SPARC_WPLT30, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_WPLT30", false,0,0x00000000,true),
HOWTO(R_SPARC_COPY, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_COPY", false,0,0x00000000,true),
HOWTO(R_SPARC_GLOB_DAT,0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_GLOB_DAT",false,0,0x00000000,true),
HOWTO(R_SPARC_JMP_SLOT,0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_JMP_SLOT",false,0,0x00000000,true),
HOWTO(R_SPARC_RELATIVE,0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_RELATIVE",false,0,0x00000000,true),
HOWTO(R_SPARC_UA32, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc,"R_SPARC_UA32", false,0,0x00000000,true),
};
struct elf_reloc_map {
@@ -121,9 +143,9 @@ static CONST struct elf_reloc_map sparc_reloc_map[] =
};
static CONST struct reloc_howto_struct *
DEFUN (bfd_elf32_bfd_reloc_type_lookup, (abfd, code),
bfd *abfd AND
bfd_reloc_code_real_type code)
bfd_elf32_bfd_reloc_type_lookup (abfd, code)
bfd *abfd;
bfd_reloc_code_real_type code;
{
int i;
for (i = 0; i < sizeof (sparc_reloc_map) / sizeof (struct elf_reloc_map); i++)
@@ -135,17 +157,683 @@ DEFUN (bfd_elf32_bfd_reloc_type_lookup, (abfd, code),
}
static void
DEFUN (elf_info_to_howto, (abfd, cache_ptr, dst),
bfd *abfd AND
arelent *cache_ptr AND
Elf32_Internal_Rela *dst)
elf_info_to_howto (abfd, cache_ptr, dst)
bfd *abfd;
arelent *cache_ptr;
Elf_Internal_Rela *dst;
{
BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_SPARC_max);
cache_ptr->howto = &elf_sparc_howto_table[ELF32_R_TYPE(dst->r_info)];
}
/* Functions for the SPARC ELF linker. */
/* The name of the dynamic interpreter. This is put in the .interp
section. */
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
/* The nop opcode we use. */
#define SPARC_NOP 0x01000000
/* The size in bytes of an entry in the procedure linkage table. */
#define PLT_ENTRY_SIZE 12
/* The first four entries in a procedure linkage table are reserved,
and the initial contents are unimportant (we zero them out).
Subsequent entries look like this. See the SVR4 ABI SPARC
supplement to see how this works. */
/* sethi %hi(.-.plt0),%g1. We fill in the address later. */
#define PLT_ENTRY_WORD0 0x03000000
/* b,a .plt0. We fill in the offset later. */
#define PLT_ENTRY_WORD1 0x30800000
/* nop. */
#define PLT_ENTRY_WORD2 SPARC_NOP
/* Create dynamic sections when linking against a dynamic object. */
static boolean
elf32_sparc_create_dynamic_sections (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
flagword flags;
register asection *s;
struct elf_link_hash_entry *h;
/* We need to create .plt, .rela.plt, .got, .dynbss, and .rela.bss
sections. */
flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
s = bfd_make_section (abfd, ".plt");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags | SEC_CODE)
|| ! bfd_set_section_alignment (abfd, s, 2))
return false;
/* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
.plt section. */
h = NULL;
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, (bfd_vma) 0,
(const char *) NULL, false, get_elf_backend_data (abfd)->collect,
(struct bfd_link_hash_entry **) &h)))
return false;
h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
/* The first four entries in .plt are reserved. */
s->_raw_size = 4 * PLT_ENTRY_SIZE;
s = bfd_make_section (abfd, ".rela.plt");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
|| ! bfd_set_section_alignment (abfd, s, 2))
return false;
s = bfd_make_section (abfd, ".got");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags)
|| ! bfd_set_section_alignment (abfd, s, 2))
return false;
/* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
section. We don't do this in the linker script because we don't
want to define the symbol if we are not creating a global offset
table. FIXME: The Solaris linker puts _GLOBAL_OFFSET_TABLE_ at
the start of the .got section, but when using the small PIC model
the .got is accessed using a signed 13 bit offset. Shouldn't
_GLOBAL_OFFSET_TABLE_ be located at .got + 4096? */
h = NULL;
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, (bfd_vma) 0,
(const char *) NULL, false, get_elf_backend_data (abfd)->collect,
(struct bfd_link_hash_entry **) &h)))
return false;
h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
/* The first global offset table entry is reserved. */
s->_raw_size += 4;
/* The .dynbss section is a place to put symbols which are defined
by dynamic objects, are referenced by regular objects, and are
not functions. We must allocate space for them in the process
image and use a R_SPARC_COPY reloc to tell the dynamic linker to
initialize them at run time. The linker script puts the .dynbss
section into the .bss section of the final image. */
s = bfd_make_section (abfd, ".dynbss");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, SEC_ALLOC))
return false;
/* The .rela.bss section holds copy relocs. */
s = bfd_make_section (abfd, ".rela.bss");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
|| ! bfd_set_section_alignment (abfd, s, 2))
return false;
return true;
}
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
change the definition to something the rest of the link can
understand. */
static boolean
elf32_sparc_adjust_dynamic_symbol (info, h)
struct bfd_link_info *info;
struct elf_link_hash_entry *h;
{
bfd *dynobj;
asection *s;
unsigned int power_of_two;
size_t align;
dynobj = elf_hash_table (info)->dynobj;
/* Make sure we know what is going on here. */
BFD_ASSERT (dynobj != NULL
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
&& (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
&& h->root.type == bfd_link_hash_defined
&& (bfd_get_flavour (h->root.u.def.section->owner)
== bfd_target_elf_flavour)
&& (elf_elfheader (h->root.u.def.section->owner)->e_type
== ET_DYN)
&& h->root.u.def.section->output_section == NULL);
/* If this is a function, put it in the procedure linkage table. We
will fill in the contents of the procedure linkage table later
(although we could actually do it here). */
if (h->type == STT_FUNC)
{
s = bfd_get_section_by_name (dynobj, ".plt");
BFD_ASSERT (s != NULL);
/* The procedure linkage table has a maximum size. */
if (s->_raw_size >= 0x400000)
{
bfd_set_error (bfd_error_bad_value);
return false;
}
/* Set the symbol to this location in the .plt. */
h->root.u.def.section = s;
h->root.u.def.value = s->_raw_size;
/* Make room for this entry. */
s->_raw_size += PLT_ENTRY_SIZE;
/* We also need to make an entry in the .rela.plt section. */
s = bfd_get_section_by_name (dynobj, ".rela.plt");
BFD_ASSERT (s != NULL);
s->_raw_size += sizeof (Elf32_External_Rela);
return true;
}
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
if (h->weakdef != NULL)
{
BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined);
h->root.u.def.section = h->weakdef->root.u.def.section;
h->root.u.def.value = h->weakdef->root.u.def.value;
h->align = (bfd_size_type) -1;
return true;
}
/* This is a reference to a symbol defined by a dynamic object which
is not a function. We must allocate it in our .dynbss section,
which will become part of the .bss section of the executable.
There will be an entry for this symbol in the .dynsym section.
The dynamic object will contain position independent code, so all
references from the dynamic object to this symbol will go through
the global offset table. The dynamic linker will use the .dynsym
entry to determine the address it must put in the global offset
table, so both the dynamic object and the regular object will
refer to the same memory location for the variable. */
s = bfd_get_section_by_name (dynobj, ".dynbss");
BFD_ASSERT (s != NULL);
/* If the symbol is currently defined in the .bss section of the
dynamic object, then it is OK to simply initialize it to zero.
If the symbol is in some other section, we must generate a
R_SPARC_COPY reloc to tell the dynamic linker to copy the initial
value out of the dynamic object and into the runtime process
image. We need to remember the offset into the .rel.bss section
we are going to use, and we coopt the align field for this
purpose (the align field is only used for common symbols, and
these symbols are always defined). It would be cleaner to use a
new field, but that would waste memory. */
if ((h->root.u.def.section->flags & SEC_LOAD) == 0)
h->align = (bfd_size_type) -1;
else
{
asection *srel;
srel = bfd_get_section_by_name (dynobj, ".rela.bss");
BFD_ASSERT (srel != NULL);
h->align = srel->_raw_size;
srel->_raw_size += sizeof (Elf32_External_Rela);
}
/* We need to figure out the alignment required for this symbol. I
have no idea how ELF linkers handle this. */
switch (h->size)
{
case 0:
case 1:
power_of_two = 0;
align = 1;
break;
case 2:
power_of_two = 1;
align = 2;
break;
case 3:
case 4:
power_of_two = 2;
align = 4;
break;
case 5:
case 6:
case 7:
case 8:
power_of_two = 3;
align = 8;
break;
default:
power_of_two = 4;
align = 16;
break;
}
/* Apply the required alignment. */
s->_raw_size = BFD_ALIGN (s->_raw_size, align);
if (power_of_two > bfd_get_section_alignment (dynobj, s))
{
if (! bfd_set_section_alignment (dynobj, s, power_of_two))
return false;
}
/* Define the symbol as being at this point in the section. */
h->root.u.def.section = s;
h->root.u.def.value = s->_raw_size;
/* Increment the section size to make room for the symbol. */
s->_raw_size += h->size;
return true;
}
/* Allocate contents for a section. */
static INLINE boolean
elf32_sparc_allocate_dynamic_section (dynobj, name)
bfd *dynobj;
const char *name;
{
register asection *s;
s = bfd_get_section_by_name (dynobj, name);
BFD_ASSERT (s != NULL);
s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
if (s->contents == NULL && s->_raw_size != 0)
{
bfd_set_error (bfd_error_no_memory);
return false;
}
return true;
}
/* Set the sizes of the dynamic sections. */
static boolean
elf32_sparc_size_dynamic_sections (output_bfd, info)
bfd *output_bfd;
struct bfd_link_info *info;
{
bfd *dynobj;
asection *s;
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
/* Set the contents of the .interp section to the interpreter. */
s = bfd_get_section_by_name (dynobj, ".interp");
BFD_ASSERT (s != NULL);
s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
/* Make space for the trailing nop in .plt. */
s = bfd_get_section_by_name (dynobj, ".plt");
BFD_ASSERT (s != NULL);
s->_raw_size += 4;
/* The adjust_dynamic_symbol entry point has determined the sizes of
the various dynamic sections. Allocate some memory for them to
hold contents. */
if (! elf32_sparc_allocate_dynamic_section (dynobj, ".plt")
|| ! elf32_sparc_allocate_dynamic_section (dynobj, ".rela.plt")
|| ! elf32_sparc_allocate_dynamic_section (dynobj, ".got")
|| ! elf32_sparc_allocate_dynamic_section (dynobj, ".rela.bss"))
return false;
/* Add some entries to the .dynamic section. We fill in the values
later, in elf32_sparc_finish_dynamic_sections, but we must add the
entries now so that we get the correct size for the .dynamic
section. */
if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
|| ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0)
|| ! bfd_elf32_add_dynamic_entry (info, DT_RELAENT,
sizeof (Elf32_External_Rela)))
return false;
return true;
}
/* Relocate a SPARC ELF section. */
static boolean
elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
contents, relocs, local_syms, local_sections)
bfd *output_bfd;
struct bfd_link_info *info;
bfd *input_bfd;
asection *input_section;
bfd_byte *contents;
Elf_Internal_Rela *relocs;
Elf_Internal_Sym *local_syms;
asection **local_sections;
{
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
{
int r_type;
const reloc_howto_type *howto;
long r_symndx;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
asection *sec;
bfd_vma relocation;
bfd_reloc_status_type r;
r_type = ELF32_R_TYPE (rel->r_info);
if (r_type < 0 || r_type >= (int) R_SPARC_max)
{
bfd_set_error (bfd_error_bad_value);
return false;
}
howto = elf_sparc_howto_table + r_type;
r_symndx = ELF32_R_SYM (rel->r_info);
if (info->relocateable)
{
/* This is a relocateable link. We don't have to change
anything, unless the reloc is against a section symbol,
in which case we have to adjust according to where the
section symbol winds up in the output section. */
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
{
sec = local_sections[r_symndx];
rel->r_addend += sec->output_offset + sym->st_value;
}
}
continue;
}
/* This is a final link. */
h = NULL;
sym = NULL;
sec = NULL;
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
relocation = (sec->output_section->vma
+ sec->output_offset
+ sym->st_value);
}
else
{
long indx;
indx = r_symndx - symtab_hdr->sh_info;
h = sym_hashes[indx];
if (h->root.type == bfd_link_hash_defined)
{
sec = h->root.u.def.section;
relocation = (h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
}
else if (h->root.type == bfd_link_hash_weak)
relocation = 0;
else
{
if (! ((*info->callbacks->undefined_symbol)
(info, h->root.root.string, input_bfd,
input_section, rel->r_offset)))
return false;
relocation = 0;
}
}
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, rel->r_addend);
if (r != bfd_reloc_ok)
{
switch (r)
{
default:
case bfd_reloc_outofrange:
abort ();
case bfd_reloc_overflow:
{
const char *name;
if (h != NULL)
name = h->root.root.string;
else
{
name = elf_string_from_elf_section (input_bfd,
symtab_hdr->sh_link,
sym->st_name);
if (name == NULL)
return false;
if (*name == '\0')
name = bfd_section_name (input_bfd, sec);
}
if (! ((*info->callbacks->reloc_overflow)
(info, name, howto->name, (bfd_vma) 0,
input_bfd, input_section, rel->r_offset)))
return false;
}
break;
}
}
}
return true;
}
/* Finish up dynamic symbol handling. We set the contents of various
dynamic sections here. */
static boolean
elf32_sparc_finish_dynamic_symbol (output_bfd, info, h, sym)
bfd *output_bfd;
struct bfd_link_info *info;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
{
/* If this symbol is not defined by a dynamic object, or is not
referenced by a regular object, ignore it. */
if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
|| (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
|| (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
{
/* Mark some specially defined symbols as absolute. */
if (strcmp (h->root.root.string, "_DYNAMIC") == 0
|| strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
|| strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
sym->st_shndx = SHN_ABS;
return true;
}
BFD_ASSERT (h->root.type == bfd_link_hash_defined);
BFD_ASSERT (h->dynindx != -1);
if (h->type == STT_FUNC)
{
asection *splt;
asection *srela;
Elf_Internal_Rela rela;
splt = h->root.u.def.section;
BFD_ASSERT (strcmp (bfd_get_section_name (splt->owner, splt), ".plt")
== 0);
srela = bfd_get_section_by_name (splt->owner, ".rela.plt");
BFD_ASSERT (srela != NULL);
/* Fill in the entry in the procedure linkage table. */
bfd_put_32 (output_bfd,
PLT_ENTRY_WORD0 + h->root.u.def.value,
splt->contents + h->root.u.def.value);
bfd_put_32 (output_bfd,
(PLT_ENTRY_WORD1
+ (((- (h->root.u.def.value + 4)) >> 2) & 0x3fffff)),
splt->contents + h->root.u.def.value + 4);
bfd_put_32 (output_bfd, PLT_ENTRY_WORD2,
splt->contents + h->root.u.def.value + 8);
/* Fill in the entry in the .rela.plt section. */
rela.r_offset = (splt->output_section->vma
+ splt->output_offset
+ h->root.u.def.value);
rela.r_info = ELF32_R_INFO (h->dynindx, R_SPARC_JMP_SLOT);
rela.r_addend = 0;
bfd_elf32_swap_reloca_out (output_bfd, &rela,
((Elf32_External_Rela *) srela->contents
+ (h->root.u.def.value / PLT_ENTRY_SIZE
- 4)));
/* Mark the symbol as undefined, rather than as defined in the
.plt section. Leave the value alone. */
sym->st_shndx = SHN_UNDEF;
}
else
{
/* This is not a function. We have already allocated memory for
it in the .bss section (via .dynbss). All we have to do here
is create a COPY reloc if required. */
if (h->align != (bfd_size_type) -1)
{
asection *s;
Elf_Internal_Rela rela;
s = bfd_get_section_by_name (h->root.u.def.section->owner,
".rela.bss");
BFD_ASSERT (s != NULL);
rela.r_offset = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
rela.r_info = ELF32_R_INFO (h->dynindx, R_SPARC_COPY);
rela.r_addend = 0;
bfd_elf32_swap_reloca_out (output_bfd, &rela,
((Elf32_External_Rela *)
(s->contents + h->align)));
}
}
return true;
}
/* Finish up the dynamic sections. */
static boolean
elf32_sparc_finish_dynamic_sections (output_bfd, info)
bfd *output_bfd;
struct bfd_link_info *info;
{
asection *splt;
asection *sgot;
asection *sdyn;
Elf32_External_Dyn *dyncon, *dynconend;
splt = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".plt");
sgot = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".got");
sdyn = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".dynamic");
BFD_ASSERT (splt != NULL && sgot != NULL && sdyn != NULL);
dyncon = (Elf32_External_Dyn *) sdyn->contents;
dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
for (; dyncon < dynconend; dyncon++)
{
Elf_Internal_Dyn dyn;
const char *name;
boolean size;
bfd_elf32_swap_dyn_in (elf_hash_table (info)->dynobj, dyncon, &dyn);
switch (dyn.d_tag)
{
case DT_PLTGOT: name = ".plt"; size = false; break;
case DT_PLTRELSZ: name = ".rela.plt"; size = true; break;
case DT_JMPREL: name = ".rela.plt"; size = false; break;
default: name = NULL; size = false; break;
}
if (name != NULL)
{
asection *s;
s = bfd_get_section_by_name (output_bfd, name);
BFD_ASSERT (s != NULL);
if (! size)
dyn.d_un.d_ptr = s->vma;
else
{
if (s->_cooked_size != 0)
dyn.d_un.d_val = s->_cooked_size;
else
dyn.d_un.d_val = s->_raw_size;
}
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
}
}
/* Clear the first four entries in the procedure linkage table, and
put a nop in the last four bytes. */
if (splt->_raw_size > 0)
{
memset (splt->contents, 0, 4 * PLT_ENTRY_SIZE);
bfd_put_32 (output_bfd, SPARC_NOP,
splt->contents + splt->_raw_size - 4);
}
/* Set the first entry in the global offset table to the address of
the dynamic section. */
if (sgot->_raw_size > 0)
bfd_put_32 (output_bfd,
sdyn->output_section->vma + sdyn->output_offset,
sgot->contents);
elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
elf_section_data (splt->output_section)->this_hdr.sh_entsize =
PLT_ENTRY_SIZE;
return true;
}
#define TARGET_BIG_SYM bfd_elf32_sparc_vec
#define TARGET_BIG_NAME "elf32-sparc"
#define ELF_ARCH bfd_arch_sparc
#define ELF_MACHINE_CODE EM_SPARC
#define ELF_MAXPAGESIZE 0x10000
#define elf_backend_create_dynamic_sections \
elf32_sparc_create_dynamic_sections
#define elf_backend_adjust_dynamic_symbol \
elf32_sparc_adjust_dynamic_symbol
#define elf_backend_size_dynamic_sections \
elf32_sparc_size_dynamic_sections
#define elf_backend_relocate_section elf32_sparc_relocate_section
#define elf_backend_finish_dynamic_symbol \
elf32_sparc_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
elf32_sparc_finish_dynamic_sections
#include "elf32-target.h"

View File

@@ -115,9 +115,24 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef elf_backend_add_symbol_hook
#define elf_backend_add_symbol_hook 0
#endif
#ifndef elf_backend_create_dynamic_sections
#define elf_backend_create_dynamic_sections 0
#endif
#ifndef elf_backend_adjust_dynamic_symbol
#define elf_backend_adjust_dynamic_symbol 0
#endif
#ifndef elf_backend_size_dynamic_sections
#define elf_backend_size_dynamic_sections 0
#endif
#ifndef elf_backend_relocate_section
#define elf_backend_relocate_section 0
#endif
#ifndef elf_backend_finish_dynamic_symbol
#define elf_backend_finish_dynamic_symbol 0
#endif
#ifndef elf_backend_finish_dynamic_sections
#define elf_backend_finish_dynamic_sections 0
#endif
#ifndef elf_backend_begin_write_processing
#define elf_backend_begin_write_processing 0
#endif
@@ -151,7 +166,12 @@ static CONST struct elf_backend_data elf32_bed =
elf_backend_fake_sections,
elf_backend_section_from_bfd_section,
elf_backend_add_symbol_hook,
elf_backend_create_dynamic_sections,
elf_backend_adjust_dynamic_symbol,
elf_backend_size_dynamic_sections,
elf_backend_relocate_section,
elf_backend_finish_dynamic_symbol,
elf_backend_finish_dynamic_sections,
elf_backend_begin_write_processing,
elf_backend_final_write_processing,
elf_backend_ecoff_debug_swap

View File

@@ -118,9 +118,24 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef elf_backend_add_symbol_hook
#define elf_backend_add_symbol_hook 0
#endif
#ifndef elf_backend_create_dynamic_sections
#define elf_backend_create_dynamic_sections 0
#endif
#ifndef elf_backend_adjust_dynamic_symbol
#define elf_backend_adjust_dynamic_symbol 0
#endif
#ifndef elf_backend_size_dynamic_sections
#define elf_backend_size_dynamic_sections 0
#endif
#ifndef elf_backend_relocate_section
#define elf_backend_relocate_section 0
#endif
#ifndef elf_backend_finish_dynamic_symbol
#define elf_backend_finish_dynamic_symbol 0
#endif
#ifndef elf_backend_finish_dynamic_sections
#define elf_backend_finish_dynamic_sections 0
#endif
#ifndef elf_backend_begin_write_processing
#define elf_backend_begin_write_processing 0
#endif
@@ -154,7 +169,12 @@ static CONST struct elf_backend_data elf64_bed =
elf_backend_fake_sections,
elf_backend_section_from_bfd_section,
elf_backend_add_symbol_hook,
elf_backend_create_dynamic_sections,
elf_backend_adjust_dynamic_symbol,
elf_backend_size_dynamic_sections,
elf_backend_relocate_section,
elf_backend_finish_dynamic_symbol,
elf_backend_finish_dynamic_sections,
elf_backend_begin_write_processing,
elf_backend_final_write_processing,
elf_backend_ecoff_debug_swap

File diff suppressed because it is too large Load Diff

View File

@@ -63,7 +63,95 @@ typedef struct
}
tc_data;
} elf_symbol_type;
/* ELF linker hash table entries. */
struct elf_link_hash_entry
{
struct bfd_link_hash_entry root;
/* Symbol index in output file. This is initialized to -1. It is
set to -2 if the symbol is used by a reloc. */
long indx;
/* Symbol size. */
bfd_size_type size;
/* Symbol alignment (common symbols only). */
bfd_size_type align;
/* Symbol index as a dynamic symbol. Initialized to -1, and remains
-1 if this is not a dynamic symbol. */
long dynindx;
/* String table index in .dynstr if this is a dynamic symbol. */
unsigned long dynstr_index;
/* If this is a weak defined symbol from a dynamic object, this
field points to a defined symbol with the same value, if there is
one. Otherwise it is NULL. */
struct elf_link_hash_entry *weakdef;
/* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */
char type;
/* Some flags; legal values follow. */
unsigned char elf_link_hash_flags;
/* Symbol is referenced by a non-shared object. */
#define ELF_LINK_HASH_REF_REGULAR 01
/* Symbol is defined by a non-shared object. */
#define ELF_LINK_HASH_DEF_REGULAR 02
/* Symbol is referenced by a shared object. */
#define ELF_LINK_HASH_REF_DYNAMIC 04
/* Symbol is defined by a shared object. */
#define ELF_LINK_HASH_DEF_DYNAMIC 010
/* Symbol is referenced by two or more shared objects. */
#define ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE 020
/* Symbol is defined by two or more shared objects. */
#define ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE 040
/* Dynamic symbol has been adjustd. */
#define ELF_LINK_HASH_DYNAMIC_ADJUSTED 0100
};
/* ELF linker hash table. */
struct elf_link_hash_table
{
struct bfd_link_hash_table root;
/* The first dynamic object found during a link. We create several
special input sections when linking against dynamic objects, and
we simply attach them to the first one found. */
bfd *dynobj;
/* The number of symbols found in the link which must be put into
the .dynsym section. */
size_t dynsymcount;
/* The string table of dynamic symbols, which becomes the .dynstr
section. */
struct strtab *dynstr;
/* The number of buckets in the hash table in the .hash section.
This is based on the number of dynamic symbols. */
size_t bucketcount;
};
/* Look up an entry in an ELF linker hash table. */
#define elf_link_hash_lookup(table, string, create, copy, follow) \
((struct elf_link_hash_entry *) \
bfd_link_hash_lookup (&(table)->root, (string), (create), \
(copy), (follow)))
/* Traverse an ELF linker hash table. */
#define elf_link_hash_traverse(table, func, info) \
(bfd_link_hash_traverse \
(&(table)->root, \
(boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \
(info)))
/* Get the ELF linker hash table from a link_info structure. */
#define elf_hash_table(p) ((struct elf_link_hash_table *) ((p)->hash))
/* Constant information held for an ELF backend. */
struct elf_backend_data
@@ -169,6 +257,44 @@ struct elf_backend_data
const Elf_Internal_Sym *, const char **name,
flagword *flags, asection **sec, bfd_vma *value));
/* The CREATE_DYNAMIC_SECTIONS function is called by the ELF backend
linker the first time it encounters a dynamic object in the link.
This function must create any sections required for dynamic
linking. The ABFD argument is a dynamic object. The .interp,
.dynamic, .dynsym, .dynstr, and .hash functions have already been
created, and this function may modify the section flags if
desired. This function will normally create the .got and .plt
sections, but different backends have different requirements. */
boolean (*elf_backend_create_dynamic_sections)
PARAMS ((bfd *abfd, struct bfd_link_info *info));
/* The ADJUST_DYNAMIC_SYMBOL function is called by the ELF backend
linker for every symbol which is defined by a dynamic object and
referenced by a regular object. This is called after all the
input files have been seen, but before the SIZE_DYNAMIC_SECTIONS
function has been called. The hash table entry should be
bfd_link_hash_defined, and it should be defined in a section from
a dynamic object. Dynamic object sections are not included in
the final link, and this function is responsible for changing the
value to something which the rest of the link can deal with.
This will normally involve adding an entry to the .plt or .got or
some such section, and setting the symbol to point to that. */
boolean (*elf_backend_adjust_dynamic_symbol)
PARAMS ((struct bfd_link_info *info, struct elf_link_hash_entry *h));
/* The SIZE_DYNAMIC_SECTIONS function is called by the ELF backend
linker after all the linker input files have been seen but before
the sections sizes have been set. This is called after
ADJUST_DYNAMIC_SYMBOL has been called on all appropriate symbols.
It is only called when linking against a dynamic object. It must
set the sizes of the dynamic sections, and may fill in their
contents as well. The generic ELF linker can handle the .dynsym,
.dynstr and .hash sections. This function must handle the
.interp section and any sections created by the
CREATE_DYNAMIC_SECTIONS entry point. */
boolean (*elf_backend_size_dynamic_sections)
PARAMS ((bfd *output_bfd, struct bfd_link_info *info));
/* The RELOCATE_SECTION function is called by the ELF backend linker
to handle the relocations for a section.
@@ -203,6 +329,24 @@ struct elf_backend_data
Elf_Internal_Rela *relocs, Elf_Internal_Sym *local_syms,
asection **local_sections));
/* The FINISH_DYNAMIC_SYMBOL function is called by the ELF backend
linker just before it writes a symbol out to the .dynsym section.
The processor backend may make any required adjustment to the
symbol. It may also take the opportunity to set contents of the
dynamic sections. Note that FINISH_DYNAMIC_SYMBOL is called on
all .dynsym symbols, while ADJUST_DYNAMIC_SYMBOL is only called
on those symbols which are defined by a dynamic object. */
boolean (*elf_backend_finish_dynamic_symbol)
PARAMS ((bfd *output_bfd, struct bfd_link_info *info,
struct elf_link_hash_entry *h, Elf_Internal_Sym *sym));
/* The FINISH_DYNAMIC_SECTIONS function is called by the ELF backend
linker just before it writes all the dynamic sections out to the
output file. The FINISH_DYNAMIC_SYMBOL will have been called on
all dynamic symbols. */
boolean (*elf_backend_finish_dynamic_sections)
PARAMS ((bfd *output_bfd, struct bfd_link_info *info));
/* A function to do any beginning processing needed for the ELF file
before building the ELF headers and computing file positions. */
void (*elf_backend_begin_write_processing) PARAMS ((bfd *));
@@ -291,48 +435,6 @@ struct elf_obj_tdata
#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size)
#define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes)
/* ELF linker hash table entries. */
struct elf_link_hash_entry
{
struct bfd_link_hash_entry root;
/* Symbol index in output file. This is initialized to -1. It is
set to -2 if the symbol is used by a reloc. */
long indx;
/* Symbol size. */
bfd_size_type size;
/* Symbol alignment (common symbols only). */
unsigned short align;
/* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */
char type;
};
/* ELF linker hash table. */
struct elf_link_hash_table
{
struct bfd_link_hash_table root;
};
/* Look up an entry in an ELF linker hash table. */
#define elf_link_hash_lookup(table, string, create, copy, follow) \
((struct elf_link_hash_entry *) \
bfd_link_hash_lookup (&(table)->root, (string), (create), \
(copy), (follow)))
/* Traverse an ELF linker hash table. */
#define elf_link_hash_traverse(table, func, info) \
(bfd_link_hash_traverse \
(&(table)->root, \
(boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \
(info)))
/* Get the ELF linker hash table from a link_info structure. */
#define elf_hash_table(p) ((struct elf_link_hash_table *) ((p)->hash))
extern char * elf_string_from_elf_section PARAMS ((bfd *, unsigned, unsigned));
extern char * elf_get_str_section PARAMS ((bfd *, unsigned));
@@ -396,6 +498,21 @@ extern boolean bfd_elf32_bfd_link_add_symbols
extern boolean bfd_elf32_bfd_final_link
PARAMS ((bfd *, struct bfd_link_info *));
extern void bfd_elf32_swap_reloc_in
PARAMS ((bfd *, Elf32_External_Rel *, Elf_Internal_Rel *));
extern void bfd_elf32_swap_reloc_out
PARAMS ((bfd *, Elf_Internal_Rel *, Elf32_External_Rel *));
extern void bfd_elf32_swap_reloca_in
PARAMS ((bfd *, Elf32_External_Rela *, Elf_Internal_Rela *));
extern void bfd_elf32_swap_reloca_out
PARAMS ((bfd *, Elf_Internal_Rela *, Elf32_External_Rela *));
extern void bfd_elf32_swap_dyn_in
PARAMS ((bfd *, const Elf32_External_Dyn *, Elf_Internal_Dyn *));
extern void bfd_elf32_swap_dyn_out
PARAMS ((bfd *, const Elf_Internal_Dyn *, Elf32_External_Dyn *));
extern boolean bfd_elf32_add_dynamic_entry
PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma));
/* If the target doesn't have reloc handling written yet: */
extern void bfd_elf32_no_info_to_howto PARAMS ((bfd *, arelent *,
Elf32_Internal_Rela *));
@@ -438,6 +555,21 @@ extern boolean bfd_elf64_bfd_link_add_symbols
extern boolean bfd_elf64_bfd_final_link
PARAMS ((bfd *, struct bfd_link_info *));
extern void bfd_elf64_swap_reloc_in
PARAMS ((bfd *, Elf64_External_Rel *, Elf_Internal_Rel *));
extern void bfd_elf64_swap_reloc_out
PARAMS ((bfd *, Elf_Internal_Rel *, Elf64_External_Rel *));
extern void bfd_elf64_swap_reloca_in
PARAMS ((bfd *, Elf64_External_Rela *, Elf_Internal_Rela *));
extern void bfd_elf64_swap_reloca_out
PARAMS ((bfd *, Elf_Internal_Rela *, Elf64_External_Rela *));
extern void bfd_elf64_swap_dyn_in
PARAMS ((bfd *, const Elf64_External_Dyn *, Elf_Internal_Dyn *));
extern void bfd_elf64_swap_dyn_out
PARAMS ((bfd *, const Elf_Internal_Dyn *, Elf64_External_Dyn *));
extern boolean bfd_elf64_add_dynamic_entry
PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma));
/* If the target doesn't have reloc handling written yet: */
extern void bfd_elf64_no_info_to_howto PARAMS ((bfd *, arelent *,
Elf64_Internal_Rela *));