From 374d2ef9053ed629c495b9f9f07b7e4f70578f81 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 26 Jul 1994 17:18:37 +0000 Subject: [PATCH] Add support for creating shared libraries under i386 ELF and SPARC ELF. Based on patches by Eric Youngdale . * libelf.h (struct elf_link_hash_entry): Remove copy_offset field. Add got_offset and plt_offset fields. (ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE): Don't define. (ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE): Don't define. (ELF_LINK_HASH_NEEDS_COPY): Define. (struct elf_backend_data): Add check_relocs field. (struct bfd_elf_section_data): Change relocs from PTR to Elf_Internal_Rela *. (struct elf_obj_tdata): Add local_got_offsets field. (elf_local_got_offsets): Define accessor macro. (bfd_elf32_link_create_dynamic_sections): Declare. (bfd_elf32_link_record_dynamic_symbol): Declare. (bfd_elf64_link_create_dynamic_sections): Declare. (bfd_elf64_link_record_dynamic_symbol): Declare. * elfcode.h (elf_slurp_reloc_table): Don't use the section data relocs field. (elf_link_record_dynamic_symbol): Make globally visible. Use macro to rename to NAME(bfd_elf,link_record_dynamic_symbol). (elf_link_add_object_symbols): If creating a shared library, put make all local symbols dynamic. Don't bother with the DYNAMIC_MULTIPLE flags. Call the check_relocs backend function if it is defined. (elf_link_create_dynamic_sections): Make globally visible. Use macro to rename to NAME(bfd_elf,link_create_dynamic_sections). If creating a shared library, make sure that _DYNAMIC is added as a dynamic symbol. (elf_link_read_relocs): New function. (NAME(bfd_elf,record_link_assignment)): If creating a shared library, always create symbols, and always make them dynamic. (elf_bfd_final_link): Permit creation of shared libraries. (elf_link_input_bfd): Use elf_link_read_relocs to get the relocs. * elf.c (_bfd_elf_link_hash_newfunc): Don't initialize copy_offset. Initialize got_offset and plt_offset. * elf32-target.h (elf_backend_check_relocs): Define as 0 if not defined. (elf32_bed): Initialize check_relocs field. * elf64-target.h (elf_backend_check_relocs): Define as 0 if not defined. (elf64_bed): Initialize check_relocs field. * elf32-i386.c (elf_howto_table): Change R_386_PLT32 and R_386_GOTPC to be pc_relative and pcrel_offset. (elf_i386_pic_plt0_entry): Define. (elf_i386_pic_plt_entry): Define. (elf_i386_create_dynamic_sections): Create a .got.plt section, and define _GLOBAL_OFFSET_TABLE_ at the start of it. If creating a shared library, make sure that _GLOBAL_OFFSET_TABLE_ is added as a dynamic symbol. Don't create .rel.bss if creating a shared library. (elf_i386_check_relocs): New function. (elf_i386_adjust_dynamic_symbol): Don't make a PLT entry if the symbol already has one. When making a PLT entry, set plt_offset. Don't create a copy reloc when creating a shared library. Don't set copy_offset, just set ELF_LINK_HASH_NEEDS_COPY. (elf_i386_allocate_dynamic_section): Remove. (elf_i386_size_dynamic_sections): Look through all the sections rather than assuming we know their names. Remove any empty reloc or plt sections. Only add a DT_DEBUG entry if not creating a shared library. Only add a DT_PLTGOT entry if there is a PLT. Add a DT_TEXTREL entry if required. (elf_i386_relocate_section): Permit undefined symbols when creating a shared library. Handle the special relocation types specially. (elf_i386_finish_dynamic_symbol): Create a PLT entry if plt_offset is set. If creating a shared library, produce a PIC PLT entry. Only mark a PLT symbol as undefined if it was not defined by a regular object file. Create a GOT entry if got_offset is set. Create a copy reloc if ELF_LINK_HASH_NEEDS_COPY is set. (elf_i386_finish_dynamic_sections): Change the handling of DT_RELSZ to simply subtract out the size of .rel.plt. If creating a shared library, produce PIC PLT code. (elf_backend_check_relocs): Define. * elf32-sparc.c (elf_sparc_howto_table): Change R_SPARC_GOT10, R_SPARC_GOT22, and R_SPARC_PC10 to not warn about reloc overflow. (elf32_sparc_create_dynamic_sections): If creating a shared library, make sure that _GLOBAL_OFFSET_TABLE_ is added as a dynamic symbol, and set the type to STT_OBJECT. Likewise for _PROCEDURE_LINKAGE_TABLE_. Don't create .rel.bss if creating a shared library. (elf32_sparc_check_relocs): New function. (elf32_sparc_adjust_dynamic_symbol): Don't make a PLT entry if the symbol already has one. When making a PLT entry, set plt_offset. Don't create a copy reloc when creating a shared library. Don't set copy_offset, just set ELF_LINK_HASH_NEEDS_COPY. (elf32_sparc_allocate_dynamic_section): Remove. (elf32_sparc_size_dynamic_sections): Look through all the sections rather than assuming we know their names. Only add a DT_DEBUG entry if not creating a shared library. Add a DT_TEXTREL entry if required. (elf32_sparc_relocate_section): Permit undefined symbols when creating a shared library. Handle the special relocation types specially. (elf32_sparc_finish_dynamic_symbol): Create a PLT entry if plt_offset is set. Only mark a PLT symbol as undefined if it was not defined by a regular object file. Create a GOT entry if got_offset is set. Create a copy reloc if ELF_LINK_HASH_NEEDS_COPY is set. (elf32_sparc_finish_dynamic_sections): Store dynobj in a local variable. (elf_backend_check_relocs): Define. --- bfd/ChangeLog | 103 ++++++++++++ bfd/elf32-target.h | 4 + bfd/elf64-target.h | 4 + bfd/elfcode.h | 384 ++++++++++++++++++++++++++++++--------------- bfd/libelf.h | 58 +++++-- 5 files changed, 412 insertions(+), 141 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index d0085567d54..0d2dd4994f8 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,106 @@ +Tue Jul 26 11:04:00 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + Add support for creating shared libraries under i386 ELF and SPARC + ELF. Based on patches by Eric Youngdale . + * libelf.h (struct elf_link_hash_entry): Remove copy_offset field. + Add got_offset and plt_offset fields. + (ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE): Don't define. + (ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE): Don't define. + (ELF_LINK_HASH_NEEDS_COPY): Define. + (struct elf_backend_data): Add check_relocs field. + (struct bfd_elf_section_data): Change relocs from PTR to + Elf_Internal_Rela *. + (struct elf_obj_tdata): Add local_got_offsets field. + (elf_local_got_offsets): Define accessor macro. + (bfd_elf32_link_create_dynamic_sections): Declare. + (bfd_elf32_link_record_dynamic_symbol): Declare. + (bfd_elf64_link_create_dynamic_sections): Declare. + (bfd_elf64_link_record_dynamic_symbol): Declare. + * elfcode.h (elf_slurp_reloc_table): Don't use the section data + relocs field. + (elf_link_record_dynamic_symbol): Make globally visible. Use + macro to rename to NAME(bfd_elf,link_record_dynamic_symbol). + (elf_link_add_object_symbols): If creating a shared library, put + make all local symbols dynamic. Don't bother with the + DYNAMIC_MULTIPLE flags. Call the check_relocs backend function if + it is defined. + (elf_link_create_dynamic_sections): Make globally visible. Use + macro to rename to NAME(bfd_elf,link_create_dynamic_sections). If + creating a shared library, make sure that _DYNAMIC is added as a + dynamic symbol. + (elf_link_read_relocs): New function. + (NAME(bfd_elf,record_link_assignment)): If creating a shared + library, always create symbols, and always make them dynamic. + (elf_bfd_final_link): Permit creation of shared libraries. + (elf_link_input_bfd): Use elf_link_read_relocs to get the relocs. + * elf.c (_bfd_elf_link_hash_newfunc): Don't initialize + copy_offset. Initialize got_offset and plt_offset. + * elf32-target.h (elf_backend_check_relocs): Define as 0 if not + defined. + (elf32_bed): Initialize check_relocs field. + * elf64-target.h (elf_backend_check_relocs): Define as 0 if not + defined. + (elf64_bed): Initialize check_relocs field. + * elf32-i386.c (elf_howto_table): Change R_386_PLT32 and + R_386_GOTPC to be pc_relative and pcrel_offset. + (elf_i386_pic_plt0_entry): Define. + (elf_i386_pic_plt_entry): Define. + (elf_i386_create_dynamic_sections): Create a .got.plt section, and + define _GLOBAL_OFFSET_TABLE_ at the start of it. If creating a + shared library, make sure that _GLOBAL_OFFSET_TABLE_ is added as a + dynamic symbol. Don't create .rel.bss if creating a shared + library. + (elf_i386_check_relocs): New function. + (elf_i386_adjust_dynamic_symbol): Don't make a PLT entry if the + symbol already has one. When making a PLT entry, set plt_offset. + Don't create a copy reloc when creating a shared library. Don't + set copy_offset, just set ELF_LINK_HASH_NEEDS_COPY. + (elf_i386_allocate_dynamic_section): Remove. + (elf_i386_size_dynamic_sections): Look through all the sections + rather than assuming we know their names. Remove any empty reloc + or plt sections. Only add a DT_DEBUG entry if not creating a + shared library. Only add a DT_PLTGOT entry if there is a PLT. + Add a DT_TEXTREL entry if required. + (elf_i386_relocate_section): Permit undefined symbols when + creating a shared library. Handle the special relocation types + specially. + (elf_i386_finish_dynamic_symbol): Create a PLT entry if plt_offset + is set. If creating a shared library, produce a PIC PLT entry. + Only mark a PLT symbol as undefined if it was not defined by a + regular object file. Create a GOT entry if got_offset is set. + Create a copy reloc if ELF_LINK_HASH_NEEDS_COPY is set. + (elf_i386_finish_dynamic_sections): Change the handling of + DT_RELSZ to simply subtract out the size of .rel.plt. If creating + a shared library, produce PIC PLT code. + (elf_backend_check_relocs): Define. + * elf32-sparc.c (elf_sparc_howto_table): Change R_SPARC_GOT10, + R_SPARC_GOT22, and R_SPARC_PC10 to not warn about reloc overflow. + (elf32_sparc_create_dynamic_sections): If creating a shared + library, make sure that _GLOBAL_OFFSET_TABLE_ is added as a + dynamic symbol, and set the type to STT_OBJECT. Likewise for + _PROCEDURE_LINKAGE_TABLE_. Don't create .rel.bss if creating a + shared library. + (elf32_sparc_check_relocs): New function. + (elf32_sparc_adjust_dynamic_symbol): Don't make a PLT entry if the + symbol already has one. When making a PLT entry, set plt_offset. + Don't create a copy reloc when creating a shared library. Don't + set copy_offset, just set ELF_LINK_HASH_NEEDS_COPY. + (elf32_sparc_allocate_dynamic_section): Remove. + (elf32_sparc_size_dynamic_sections): Look through all the sections + rather than assuming we know their names. Only add a DT_DEBUG + entry if not creating a shared library. Add a DT_TEXTREL entry if + required. + (elf32_sparc_relocate_section): Permit undefined symbols when + creating a shared library. Handle the special relocation types + specially. + (elf32_sparc_finish_dynamic_symbol): Create a PLT entry if plt_offset + is set. Only mark a PLT symbol as undefined if it was not defined + by a regular object file. Create a GOT entry if got_offset is + set. Create a copy reloc if ELF_LINK_HASH_NEEDS_COPY is set. + (elf32_sparc_finish_dynamic_sections): Store dynobj in a local + variable. + (elf_backend_check_relocs): Define. + Mon Jul 25 12:21:07 1994 Stan Shebs (shebs@andros.cygnus.com) * configure.in (pc532mach_vec): Change to pc532machaout_vec. diff --git a/bfd/elf32-target.h b/bfd/elf32-target.h index 67dabecc71f..c1091f2a9bb 100644 --- a/bfd/elf32-target.h +++ b/bfd/elf32-target.h @@ -121,6 +121,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef elf_backend_create_dynamic_sections #define elf_backend_create_dynamic_sections 0 #endif +#ifndef elf_backend_check_relocs +#define elf_backend_check_relocs 0 +#endif #ifndef elf_backend_adjust_dynamic_symbol #define elf_backend_adjust_dynamic_symbol 0 #endif @@ -171,6 +174,7 @@ static CONST struct elf_backend_data elf32_bed = elf_backend_add_symbol_hook, elf_backend_link_output_symbol_hook, elf_backend_create_dynamic_sections, + elf_backend_check_relocs, elf_backend_adjust_dynamic_symbol, elf_backend_size_dynamic_sections, elf_backend_relocate_section, diff --git a/bfd/elf64-target.h b/bfd/elf64-target.h index a85b5d0d3a7..006d60cbdb0 100644 --- a/bfd/elf64-target.h +++ b/bfd/elf64-target.h @@ -124,6 +124,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef elf_backend_create_dynamic_sections #define elf_backend_create_dynamic_sections 0 #endif +#ifndef elf_backend_check_relocs +#define elf_backend_check_relocs 0 +#endif #ifndef elf_backend_adjust_dynamic_symbol #define elf_backend_adjust_dynamic_symbol 0 #endif @@ -174,6 +177,7 @@ static CONST struct elf_backend_data elf64_bed = elf_backend_add_symbol_hook, elf_backend_link_output_symbol_hook, elf_backend_create_dynamic_sections, + elf_backend_check_relocs, elf_backend_adjust_dynamic_symbol, elf_backend_size_dynamic_sections, elf_backend_relocate_section, diff --git a/bfd/elfcode.h b/bfd/elfcode.h index fd02038f0a0..49f24c4cf57 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -116,6 +116,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define elf_find_section NAME(bfd_elf,find_section) #define elf_bfd_link_add_symbols NAME(bfd_elf,bfd_link_add_symbols) #define elf_add_dynamic_entry NAME(bfd_elf,add_dynamic_entry) +#define elf_link_create_dynamic_sections \ + NAME(bfd_elf,link_create_dynamic_sections) +#define elf_link_record_dynamic_symbol \ + NAME(bfd_elf,link_record_dynamic_symbol) #define elf_bfd_final_link NAME(bfd_elf,bfd_final_link) #if ARCH_SIZE == 64 @@ -2931,23 +2935,19 @@ elf_slurp_reloc_table (abfd, asect, symbols) && (asect->reloc_count == d->rel_hdr.sh_size / d->rel_hdr.sh_entsize)); - native_relocs = (bfd_byte *) elf_section_data (asect)->relocs; - if (native_relocs == NULL) + allocated = (PTR) malloc (d->rel_hdr.sh_size); + if (allocated == NULL) { - allocated = (PTR) malloc (d->rel_hdr.sh_size); - if (allocated == NULL) - { - bfd_set_error (bfd_error_no_memory); - goto error_return; - } + bfd_set_error (bfd_error_no_memory); + goto error_return; + } - if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0 - || (bfd_read (allocated, 1, d->rel_hdr.sh_size, abfd) - != d->rel_hdr.sh_size)) - goto error_return; + if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0 + || (bfd_read (allocated, 1, d->rel_hdr.sh_size, abfd) + != d->rel_hdr.sh_size)) + goto error_return; - native_relocs = (bfd_byte *) allocated; - } + native_relocs = (bfd_byte *) allocated; relents = ((arelent *) bfd_alloc (abfd, asect->reloc_count * sizeof (arelent))); @@ -3750,10 +3750,8 @@ static boolean elf_link_add_object_symbols PARAMS ((bfd *, struct bfd_link_info *)); static boolean elf_link_add_archive_symbols PARAMS ((bfd *, struct bfd_link_info *)); -static INLINE boolean elf_link_record_dynamic_symbol - PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); -static boolean elf_link_create_dynamic_sections - PARAMS ((bfd *, struct bfd_link_info *)); +static Elf_Internal_Rela *elf_link_read_relocs + PARAMS ((bfd *, asection *, PTR, Elf_Internal_Rela *, boolean)); static boolean elf_adjust_dynamic_symbol PARAMS ((struct elf_link_hash_entry *, PTR)); @@ -3947,7 +3945,7 @@ elf_link_add_archive_symbols (abfd, info) read the input files, since we need to have a list of all of them before we can determine the final sizes of the output sections. */ -static INLINE boolean +INLINE boolean elf_link_record_dynamic_symbol (info, h) struct bfd_link_info *info; struct elf_link_hash_entry *h; @@ -3977,6 +3975,8 @@ elf_link_add_object_symbols (abfd, info) const Elf_Internal_Sym *, const char **, flagword *, asection **, bfd_vma *)); + boolean (*check_relocs) PARAMS ((bfd *, struct bfd_link_info *, + asection *, const Elf_Internal_Rela *)); boolean collect; Elf_Internal_Shdr *hdr; size_t symcount; @@ -4055,9 +4055,9 @@ elf_link_add_object_symbols (abfd, info) dynamic = true; - /* You can't use -r against a dynamic object. There's no hope - of using a dynamic object which does not exactly match the - format of the output file. */ + /* You can't use -r against a dynamic object. Also, there's no + hope of using a dynamic object which does not exactly match + the format of the output file. */ if (info->relocateable || info->hash->creator != abfd->xvec) { @@ -4143,7 +4143,6 @@ elf_link_add_object_symbols (abfd, info) strindex = bfd_add_to_strtab (abfd, elf_hash_table (info)->dynstr, name); - if (strindex == (unsigned long) -1) goto error_return; if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex)) @@ -4334,6 +4333,7 @@ elf_link_add_object_symbols (abfd, info) weaks = *sym_hash; } + /* Get the alignment of a common symbol. */ if (sym.st_shndx == SHN_COMMON && h->root.type == bfd_link_hash_common) h->root.u.c.alignment_power = bfd_log2 (sym.st_value); @@ -4344,7 +4344,7 @@ elf_link_add_object_symbols (abfd, info) boolean dynsym; int new_flag; - /* Remember the symbol size, type and alignment. */ + /* Remember the symbol size and type. */ if (sym.st_size != 0) { /* FIXME: We should probably somehow give a warning if @@ -4372,8 +4372,9 @@ elf_link_add_object_symbols (abfd, info) new_flag = ELF_LINK_HASH_REF_REGULAR; else new_flag = ELF_LINK_HASH_DEF_REGULAR; - if ((old_flags & (ELF_LINK_HASH_DEF_DYNAMIC - | ELF_LINK_HASH_REF_DYNAMIC)) != 0) + if (info->shared + || (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_REF_DYNAMIC)) != 0) dynsym = true; } else @@ -4382,20 +4383,10 @@ elf_link_add_object_symbols (abfd, info) new_flag = ELF_LINK_HASH_REF_DYNAMIC; else new_flag = ELF_LINK_HASH_DEF_DYNAMIC; - if ((old_flags & new_flag) != 0) - { - if (! definition) - new_flag = ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE; - else - new_flag = ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE; - dynsym = true; - } - else - { - if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR - | ELF_LINK_HASH_REF_REGULAR)) != 0) - dynsym = true; - } + if ((old_flags & new_flag) != 0 + || (old_flags & (ELF_LINK_HASH_DEF_REGULAR + | ELF_LINK_HASH_REF_REGULAR)) != 0) + dynsym = true; } h->elf_link_hash_flags |= new_flag; @@ -4466,7 +4457,65 @@ elf_link_add_object_symbols (abfd, info) } if (buf != NULL) - free (buf); + { + free (buf); + buf = NULL; + } + + /* If this object is the same format as the output object, and it is + not a shared library, then let the backend look through the + relocs. + + This is required to build global offset table entries and to + arrange for dynamic relocs. It is not required for the + particular common case of linking non PIC code, even when linking + against shared libraries, but unfortunately there is no way of + knowing whether an object file has been compiled PIC or not. + Looking through the relocs is not particularly time consuming. + The problem is that we must either (1) keep the relocs in memory, + which causes the linker to require additional runtime memory or + (2) read the relocs twice from the input file, which wastes time. + This would be a good case for using mmap. + + I have no idea how to handle linking PIC code into a file of a + different format. It probably can't be done. */ + check_relocs = get_elf_backend_data (abfd)->check_relocs; + if (! dynamic + && abfd->xvec == info->hash->creator + && check_relocs != NULL) + { + asection *o; + + for (o = abfd->sections; o != NULL; o = o->next) + { + Elf_Internal_Rela *internal_relocs; + boolean ok; + + if ((o->flags & SEC_RELOC) == 0 + || o->reloc_count == 0) + continue; + + /* I believe we can ignore the relocs for any section which + does not form part of the final process image, such as a + debugging section. */ + if ((o->flags & SEC_ALLOC) == 0) + continue; + + internal_relocs = elf_link_read_relocs (abfd, o, (PTR) NULL, + (Elf_Internal_Rela *) NULL, + info->keep_memory); + if (internal_relocs == NULL) + goto error_return; + + ok = (*check_relocs) (abfd, info, o, internal_relocs); + + if (! info->keep_memory) + free (internal_relocs); + + if (! ok) + goto error_return; + } + } return true; @@ -4485,7 +4534,7 @@ elf_link_add_object_symbols (abfd, info) are assigned to the output sections. We work out the actual contents and size of these sections later. */ -static boolean +boolean elf_link_create_dynamic_sections (abfd, info) bfd *abfd; struct bfd_link_info *info; @@ -4509,6 +4558,25 @@ elf_link_create_dynamic_sections (abfd, info) return false; } + s = bfd_make_section (abfd, ".dynsym"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return false; + + /* The first .dynsym symbol is a dummy. */ + elf_hash_table (info)->dynsymcount = 1; + + s = bfd_make_section (abfd, ".dynstr"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)) + return false; + + /* Create a strtab to hold the dynamic symbol names. */ + elf_hash_table (info)->dynstr = bfd_new_strtab (abfd); + if (elf_hash_table (info)->dynstr == NULL) + return false; + s = bfd_make_section (abfd, ".dynamic"); if (s == NULL || ! bfd_set_section_flags (abfd, s, flags) @@ -4530,24 +4598,9 @@ elf_link_create_dynamic_sections (abfd, info) (struct bfd_link_hash_entry **) &h))) return false; h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; - - s = bfd_make_section (abfd, ".dynsym"); - if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) - || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) - return false; - - /* The first .dynsym symbol is a dummy. */ - elf_hash_table (info)->dynsymcount = 1; - - s = bfd_make_section (abfd, ".dynstr"); - if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)) - return false; - - /* Create a strtab to hold the dynamic symbol names. */ - elf_hash_table (info)->dynstr = bfd_new_strtab (abfd); - if (elf_hash_table (info)->dynstr == NULL) + + if (info->shared + && ! elf_link_record_dynamic_symbol (info, h)) return false; s = bfd_make_section (abfd, ".hash"); @@ -4604,6 +4657,122 @@ elf_add_dynamic_entry (info, tag, val) return true; } +/* Read and swap the relocs for a section. They may have been cached. + If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are not NULL, + they are used as buffers to read into. They are known to be large + enough. If the INTERNAL_RELOCS relocs argument is NULL, the return + value is allocated using either malloc or bfd_alloc, according to + the KEEP_MEMORY argument. */ + +static Elf_Internal_Rela * +elf_link_read_relocs (abfd, o, external_relocs, internal_relocs, keep_memory) + bfd *abfd; + asection *o; + PTR external_relocs; + Elf_Internal_Rela *internal_relocs; + boolean keep_memory; +{ + Elf_Internal_Shdr *rel_hdr; + PTR alloc1 = NULL; + Elf_Internal_Rela *alloc2 = NULL; + + if (elf_section_data (o)->relocs != NULL) + return elf_section_data (o)->relocs; + + if (o->reloc_count == 0) + return NULL; + + rel_hdr = &elf_section_data (o)->rel_hdr; + + if (internal_relocs == NULL) + { + size_t size; + + size = o->reloc_count * sizeof (Elf_Internal_Rela); + if (keep_memory) + internal_relocs = (Elf_Internal_Rela *) bfd_alloc (abfd, size); + else + internal_relocs = alloc2 = (Elf_Internal_Rela *) malloc (size); + if (internal_relocs == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + } + + if (external_relocs == NULL) + { + alloc1 = (PTR) malloc (rel_hdr->sh_size); + if (alloc1 == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + external_relocs = alloc1; + } + + if ((bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0) + || (bfd_read (external_relocs, 1, rel_hdr->sh_size, abfd) + != rel_hdr->sh_size)) + goto error_return; + + /* Swap in the relocs. For convenience, we always produce an + Elf_Internal_Rela array; if the relocs are Rel, we set the addend + to 0. */ + if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + { + Elf_External_Rel *erel; + Elf_External_Rel *erelend; + Elf_Internal_Rela *irela; + + erel = (Elf_External_Rel *) external_relocs; + erelend = erel + o->reloc_count; + irela = internal_relocs; + for (; erel < erelend; erel++, irela++) + { + Elf_Internal_Rel irel; + + elf_swap_reloc_in (abfd, erel, &irel); + irela->r_offset = irel.r_offset; + irela->r_info = irel.r_info; + irela->r_addend = 0; + } + } + else + { + Elf_External_Rela *erela; + Elf_External_Rela *erelaend; + Elf_Internal_Rela *irela; + + BFD_ASSERT (rel_hdr->sh_entsize == sizeof (Elf_External_Rela)); + + erela = (Elf_External_Rela *) external_relocs; + erelaend = erela + o->reloc_count; + irela = internal_relocs; + for (; erela < erelaend; erela++, irela++) + elf_swap_reloca_in (abfd, erela, irela); + } + + /* Cache the results for next time, if we can. */ + if (keep_memory) + elf_section_data (o)->relocs = internal_relocs; + + if (alloc1 != NULL) + free (alloc1); + + /* Don't free alloc2, since if it was allocated we are passing it + back (under the name of internal_relocs). */ + + return internal_relocs; + + error_return: + if (alloc1 != NULL) + free (alloc1); + if (alloc2 != NULL) + free (alloc2); + return NULL; +} + /* Record an assignment to a symbol made by a linker script. We need this in case some dynamic object refers to this symbol. */ @@ -4617,17 +4786,20 @@ NAME(bfd_elf,record_link_assignment) (output_bfd, info, name) struct elf_link_hash_entry *h; /* This is called after we have examined all the input objects. If - the symbol does not exist, it merely means that no object refers - to it, and we can just ignore it at this point. */ + we are generating a shared library, we always output these + symbols. Otherwise, if the symbol does not exist, it merely + means that no object refers to it, and we can just ignore it at + this point. */ h = elf_link_hash_lookup (elf_hash_table (info), name, - false, false, false); + info->shared, info->shared, false); if (h == NULL) - return true; + return ! info->shared; h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; - if ((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC - | ELF_LINK_HASH_REF_DYNAMIC)) != 0 + if (((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_REF_DYNAMIC)) != 0 + || info->shared) && h->dynindx == -1) { if (! elf_link_record_dynamic_symbol (info, h)) @@ -4969,12 +5141,7 @@ elf_bfd_final_link (abfd, info) struct elf_backend_data *bed = get_elf_backend_data (abfd); if (info->shared) - { - fprintf (stderr, - "Generating ELF shared libraries is not yet supported\n"); - bfd_set_error (bfd_error_invalid_operation); - return false; - } + abfd->flags |= DYNAMIC; dynobj = elf_hash_table (info)->dynobj; @@ -5936,8 +6103,6 @@ elf_link_input_bfd (finfo, input_bfd) /* Relocate the contents of each section. */ for (o = input_bfd->sections; o != NULL; o = o->next) { - Elf_Internal_Shdr *input_rel_hdr; - if ((o->flags & SEC_HAS_CONTENTS) == 0) continue; @@ -5956,59 +6121,16 @@ elf_link_input_bfd (finfo, input_bfd) if ((o->flags & SEC_RELOC) != 0) { - PTR external_relocs; - - /* Get the external relocs. They may have been cached. */ - external_relocs = elf_section_data (o)->relocs; - if (external_relocs == NULL) - { - input_rel_hdr = &elf_section_data (o)->rel_hdr; - if ((bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET) - != 0) - || (bfd_read (finfo->external_relocs, 1, - input_rel_hdr->sh_size, input_bfd) - != input_rel_hdr->sh_size)) - return false; - external_relocs = finfo->external_relocs; - } - - /* Swap in the relocs. For convenience, we always produce - an Elf_Internal_Rela array; if the relocs are Rel, we set - the addend to 0. */ - if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) - { - Elf_External_Rel *erel; - Elf_External_Rel *erelend; - Elf_Internal_Rela *irela; - - erel = (Elf_External_Rel *) external_relocs; - erelend = erel + o->reloc_count; - irela = finfo->internal_relocs; - for (; erel < erelend; erel++, irela++) - { - Elf_Internal_Rel irel; - - elf_swap_reloc_in (input_bfd, erel, &irel); - irela->r_offset = irel.r_offset; - irela->r_info = irel.r_info; - irela->r_addend = 0; - } - } - else - { - Elf_External_Rela *erela; - Elf_External_Rela *erelaend; - Elf_Internal_Rela *irela; - - BFD_ASSERT (input_rel_hdr->sh_entsize - == sizeof (Elf_External_Rela)); - - erela = (Elf_External_Rela *) external_relocs; - erelaend = erela + o->reloc_count; - irela = finfo->internal_relocs; - for (; erela < erelaend; erela++, irela++) - elf_swap_reloca_in (input_bfd, erela, irela); - } + Elf_Internal_Rela *internal_relocs; + + /* Get the swapped relocs. */ + internal_relocs = elf_link_read_relocs (input_bfd, o, + finfo->external_relocs, + finfo->internal_relocs, + false); + if (internal_relocs == NULL + && o->reloc_count > 0) + return false; /* Relocate the section by invoking a back end routine. @@ -6033,7 +6155,7 @@ elf_link_input_bfd (finfo, input_bfd) if (! (*relocate_section) (output_bfd, finfo->info, input_bfd, o, finfo->contents, - finfo->internal_relocs, + internal_relocs, finfo->internal_syms, finfo->sections, finfo->symstrtab->tab)) @@ -6044,11 +6166,12 @@ elf_link_input_bfd (finfo, input_bfd) Elf_Internal_Rela *irela; Elf_Internal_Rela *irelaend; struct elf_link_hash_entry **rel_hash; + Elf_Internal_Shdr *input_rel_hdr; Elf_Internal_Shdr *output_rel_hdr; /* Adjust the reloc addresses and symbol indices. */ - irela = finfo->internal_relocs; + irela = internal_relocs; irelaend = irela + o->reloc_count; rel_hash = (elf_section_data (o->output_section)->rel_hashes + o->output_section->reloc_count); @@ -6164,10 +6287,11 @@ elf_link_input_bfd (finfo, input_bfd) } /* Swap out the relocs. */ + input_rel_hdr = &elf_section_data (o)->rel_hdr; output_rel_hdr = &elf_section_data (o->output_section)->rel_hdr; BFD_ASSERT (output_rel_hdr->sh_entsize == input_rel_hdr->sh_entsize); - irela = finfo->internal_relocs; + irela = internal_relocs; irelaend = irela + o->reloc_count; if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) { diff --git a/bfd/libelf.h b/bfd/libelf.h index f14ac95ccee..d43f135a570 100644 --- a/bfd/libelf.h +++ b/bfd/libelf.h @@ -89,9 +89,18 @@ struct elf_link_hash_entry one. Otherwise it is NULL. */ struct elf_link_hash_entry *weakdef; - /* If we need to generate a COPY reloc, the processor specific - backend uses this to hold the offset into the reloc section. */ - bfd_vma copy_offset; + /* If this symbol requires an entry in the global offset table, the + processor specific backend uses this field to hold the offset + into the .got section. If this field is -1, then the symbol does + not require a global offset table entry. */ + bfd_vma got_offset; + + /* If this symbol requires an entry in the procedure linkage table, + the processor specific backend uses these two fields to hold the + offset into the procedure linkage section and the offset into the + .got section. If plt_offset is -1, then the symbol does not + require an entry in the procedure linkage table. */ + bfd_vma plt_offset; /* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */ char type; @@ -106,14 +115,12 @@ struct elf_link_hash_entry #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 +#define ELF_LINK_HASH_DYNAMIC_ADJUSTED 020 /* Symbol is defined as weak. */ -#define ELF_LINK_HASH_DEFINED_WEAK 0200 +#define ELF_LINK_HASH_DEFINED_WEAK 040 + /* Symbol needs a copy reloc. */ +#define ELF_LINK_HASH_NEEDS_COPY 0100 }; /* ELF linker hash table. */ @@ -277,6 +284,20 @@ struct elf_backend_data boolean (*elf_backend_create_dynamic_sections) PARAMS ((bfd *abfd, struct bfd_link_info *info)); + /* The CHECK_RELOCS function is called by the add_symbols phase of + the ELF backend linker. It is called once for each section with + relocs of an object file, just after the symbols for the object + file have been added to the global linker hash table. The + function must look through the relocs and do any special handling + required. This generally means allocating space in the global + offset table, and perhaps allocating space for a reloc. The + relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. */ + boolean (*check_relocs) + PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o, + const Elf_Internal_Rela *relocs)); + /* 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 @@ -396,8 +417,10 @@ struct bfd_elf_section_data { /* Used by the backend linker to store the symbol hash table entries associated with relocs against global symbols. */ struct elf_link_hash_entry **rel_hashes; - /* A pointer to the unswapped external relocs; this may be NULL. */ - PTR relocs; + /* A pointer to the swapped relocs. If the section uses REL relocs, + rather than RELA, all the r_addend fields will be zero. This + pointer may be NULL. It is used by the backend linker. */ + Elf_Internal_Rela *relocs; }; #define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd) @@ -443,6 +466,10 @@ struct elf_obj_tdata minus the sh_info field of the symbol table header. */ struct elf_link_hash_entry **sym_hashes; + /* A mapping from local symbols to offsets into the global offset + table, used when linking. This is indexed by the symbol index. */ + bfd_vma *local_got_offsets; + /* The linker ELF emulation code needs to let the backend ELF linker know what filename should be used for a dynamic object if the dynamic object is found using a search. This field is used to @@ -473,6 +500,7 @@ struct elf_obj_tdata #define elf_gp(bfd) (elf_tdata(bfd) -> gp) #define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size) #define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes) +#define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got_offsets) #define elf_dt_needed_name(bfd) (elf_tdata(bfd) -> dt_needed_name) #define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) @@ -565,6 +593,10 @@ 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)); +extern boolean bfd_elf32_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_elf32_link_record_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); /* If the target doesn't have reloc handling written yet: */ extern void bfd_elf32_no_info_to_howto PARAMS ((bfd *, arelent *, @@ -626,6 +658,10 @@ 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)); +extern boolean bfd_elf64_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_elf64_link_record_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); /* If the target doesn't have reloc handling written yet: */ extern void bfd_elf64_no_info_to_howto PARAMS ((bfd *, arelent *, -- 2.30.2