X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf.c;h=1e162b0b53ba5c400aff0adfef3d1a60291f05ba;hb=dbb410c3e20602a6d4be32a6833a9b7f5b0f1ae9;hp=4978957833309a513d10d883eb62b0b3e4fa8f28;hpb=b944e7e855f74a833fb8ae9f60e4e13a0947ab73;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf.c b/bfd/elf.c index 4978957833..a3a83e4b32 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1,5 +1,6 @@ /* ELF executable support for BFD. - Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -31,6 +32,8 @@ SECTION haven't bothered yet. */ +/* For sparc64-cross-sparc32. */ +#define _SYSCALL32 #include "bfd.h" #include "sysdep.h" #include "bfdlink.h" @@ -45,16 +48,180 @@ static int elf_sort_sections PARAMS ((const PTR, const PTR)); static boolean assign_file_positions_for_segments PARAMS ((bfd *)); static boolean assign_file_positions_except_relocs PARAMS ((bfd *)); static boolean prep_headers PARAMS ((bfd *)); -static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **)); +static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **, int)); static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *)); +static char *elf_read PARAMS ((bfd *, file_ptr, bfd_size_type)); +static boolean setup_group PARAMS ((bfd *, Elf_Internal_Shdr *, asection *)); +static void elf_fake_sections PARAMS ((bfd *, asection *, PTR)); +static void set_group_contents PARAMS ((bfd *, asection *, PTR)); +static boolean assign_section_numbers PARAMS ((bfd *)); +static INLINE int sym_is_global PARAMS ((bfd *, asymbol *)); +static boolean elf_map_symbols PARAMS ((bfd *)); +static bfd_size_type get_program_header_size PARAMS ((bfd *)); +static boolean elfcore_read_notes PARAMS ((bfd *, file_ptr, bfd_size_type)); +static boolean elf_find_function PARAMS ((bfd *, asection *, asymbol **, + bfd_vma, const char **, + const char **)); +static int elfcore_make_pid PARAMS ((bfd *)); +static boolean elfcore_maybe_make_sect PARAMS ((bfd *, char *, asection *)); +static boolean elfcore_make_note_pseudosection PARAMS ((bfd *, char *, + Elf_Internal_Note *)); +static boolean elfcore_grok_prfpreg PARAMS ((bfd *, Elf_Internal_Note *)); +static boolean elfcore_grok_prxfpreg PARAMS ((bfd *, Elf_Internal_Note *)); +static boolean elfcore_grok_note PARAMS ((bfd *, Elf_Internal_Note *)); + +/* Swap version information in and out. The version information is + currently size independent. If that ever changes, this code will + need to move into elfcode.h. */ + +/* Swap in a Verdef structure. */ + +void +_bfd_elf_swap_verdef_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Verdef *src; + Elf_Internal_Verdef *dst; +{ + dst->vd_version = H_GET_16 (abfd, src->vd_version); + dst->vd_flags = H_GET_16 (abfd, src->vd_flags); + dst->vd_ndx = H_GET_16 (abfd, src->vd_ndx); + dst->vd_cnt = H_GET_16 (abfd, src->vd_cnt); + dst->vd_hash = H_GET_32 (abfd, src->vd_hash); + dst->vd_aux = H_GET_32 (abfd, src->vd_aux); + dst->vd_next = H_GET_32 (abfd, src->vd_next); +} + +/* Swap out a Verdef structure. */ + +void +_bfd_elf_swap_verdef_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Verdef *src; + Elf_External_Verdef *dst; +{ + H_PUT_16 (abfd, src->vd_version, dst->vd_version); + H_PUT_16 (abfd, src->vd_flags, dst->vd_flags); + H_PUT_16 (abfd, src->vd_ndx, dst->vd_ndx); + H_PUT_16 (abfd, src->vd_cnt, dst->vd_cnt); + H_PUT_32 (abfd, src->vd_hash, dst->vd_hash); + H_PUT_32 (abfd, src->vd_aux, dst->vd_aux); + H_PUT_32 (abfd, src->vd_next, dst->vd_next); +} + +/* Swap in a Verdaux structure. */ + +void +_bfd_elf_swap_verdaux_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Verdaux *src; + Elf_Internal_Verdaux *dst; +{ + dst->vda_name = H_GET_32 (abfd, src->vda_name); + dst->vda_next = H_GET_32 (abfd, src->vda_next); +} + +/* Swap out a Verdaux structure. */ + +void +_bfd_elf_swap_verdaux_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Verdaux *src; + Elf_External_Verdaux *dst; +{ + H_PUT_32 (abfd, src->vda_name, dst->vda_name); + H_PUT_32 (abfd, src->vda_next, dst->vda_next); +} + +/* Swap in a Verneed structure. */ + +void +_bfd_elf_swap_verneed_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Verneed *src; + Elf_Internal_Verneed *dst; +{ + dst->vn_version = H_GET_16 (abfd, src->vn_version); + dst->vn_cnt = H_GET_16 (abfd, src->vn_cnt); + dst->vn_file = H_GET_32 (abfd, src->vn_file); + dst->vn_aux = H_GET_32 (abfd, src->vn_aux); + dst->vn_next = H_GET_32 (abfd, src->vn_next); +} + +/* Swap out a Verneed structure. */ + +void +_bfd_elf_swap_verneed_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Verneed *src; + Elf_External_Verneed *dst; +{ + H_PUT_16 (abfd, src->vn_version, dst->vn_version); + H_PUT_16 (abfd, src->vn_cnt, dst->vn_cnt); + H_PUT_32 (abfd, src->vn_file, dst->vn_file); + H_PUT_32 (abfd, src->vn_aux, dst->vn_aux); + H_PUT_32 (abfd, src->vn_next, dst->vn_next); +} + +/* Swap in a Vernaux structure. */ + +void +_bfd_elf_swap_vernaux_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Vernaux *src; + Elf_Internal_Vernaux *dst; +{ + dst->vna_hash = H_GET_32 (abfd, src->vna_hash); + dst->vna_flags = H_GET_16 (abfd, src->vna_flags); + dst->vna_other = H_GET_16 (abfd, src->vna_other); + dst->vna_name = H_GET_32 (abfd, src->vna_name); + dst->vna_next = H_GET_32 (abfd, src->vna_next); +} + +/* Swap out a Vernaux structure. */ + +void +_bfd_elf_swap_vernaux_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Vernaux *src; + Elf_External_Vernaux *dst; +{ + H_PUT_32 (abfd, src->vna_hash, dst->vna_hash); + H_PUT_16 (abfd, src->vna_flags, dst->vna_flags); + H_PUT_16 (abfd, src->vna_other, dst->vna_other); + H_PUT_32 (abfd, src->vna_name, dst->vna_name); + H_PUT_32 (abfd, src->vna_next, dst->vna_next); +} + +/* Swap in a Versym structure. */ + +void +_bfd_elf_swap_versym_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Versym *src; + Elf_Internal_Versym *dst; +{ + dst->vs_vers = H_GET_16 (abfd, src->vs_vers); +} + +/* Swap out a Versym structure. */ + +void +_bfd_elf_swap_versym_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Versym *src; + Elf_External_Versym *dst; +{ + H_PUT_16 (abfd, src->vs_vers, dst->vs_vers); +} /* Standard ELF hash function. Do not change this function; you will - cause invalid hash tables to be generated. (Well, you would if this - were being used yet.) */ + cause invalid hash tables to be generated. */ + unsigned long -bfd_elf_hash (name) - CONST unsigned char *name; +bfd_elf_hash (namearg) + const char *namearg; { + const unsigned char *name = (const unsigned char *) namearg; unsigned long h = 0; unsigned long g; int ch; @@ -65,7 +232,9 @@ bfd_elf_hash (name) if ((g = (h & 0xf0000000)) != 0) { h ^= g >> 24; - h &= ~g; + /* The ELF ABI says `h &= ~g', but this is equivalent in + this case and on some machines one insn instead of two. */ + h ^= g; } } return h; @@ -73,21 +242,21 @@ bfd_elf_hash (name) /* Read a specified number of bytes at a specified offset in an ELF file, into a newly allocated buffer, and return a pointer to the - buffer. */ + buffer. */ static char * elf_read (abfd, offset, size) - bfd * abfd; - long offset; - unsigned int size; + bfd *abfd; + file_ptr offset; + bfd_size_type size; { char *buf; if ((buf = bfd_alloc (abfd, size)) == NULL) return NULL; - if (bfd_seek (abfd, offset, SEEK_SET) == -1) + if (bfd_seek (abfd, offset, SEEK_SET) != 0) return NULL; - if (bfd_read ((PTR) buf, size, 1, abfd) != size) + if (bfd_bread ((PTR) buf, size, abfd) != size) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_file_truncated); @@ -97,30 +266,38 @@ elf_read (abfd, offset, size) } boolean -elf_mkobject (abfd) - bfd * abfd; +bfd_elf_mkobject (abfd) + bfd *abfd; { - /* this just does initialization */ - /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */ - elf_tdata (abfd) = (struct elf_obj_tdata *) - bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); + /* This just does initialization. */ + /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */ + bfd_size_type amt = sizeof (struct elf_obj_tdata); + elf_tdata (abfd) = (struct elf_obj_tdata *) bfd_zalloc (abfd, amt); if (elf_tdata (abfd) == 0) return false; - /* since everything is done at close time, do we need any - initialization? */ + /* Since everything is done at close time, do we need any + initialization? */ return true; } +boolean +bfd_elf_mkcorefile (abfd) + bfd *abfd; +{ + /* I think this can be done just like an object file. */ + return bfd_elf_mkobject (abfd); +} + char * bfd_elf_get_str_section (abfd, shindex) - bfd * abfd; + bfd *abfd; unsigned int shindex; { Elf_Internal_Shdr **i_shdrp; char *shstrtab = NULL; - unsigned int offset; - unsigned int shstrtabsize; + file_ptr offset; + bfd_size_type shstrtabsize; i_shdrp = elf_elfsections (abfd); if (i_shdrp == 0 || i_shdrp[shindex] == 0) @@ -129,7 +306,7 @@ bfd_elf_get_str_section (abfd, shindex) shstrtab = (char *) i_shdrp[shindex]->contents; if (shstrtab == NULL) { - /* No cached one, attempt to read, and cache what we read. */ + /* No cached one, attempt to read, and cache what we read. */ offset = i_shdrp[shindex]->sh_offset; shstrtabsize = i_shdrp[shindex]->sh_size; shstrtab = elf_read (abfd, offset, shstrtabsize); @@ -140,7 +317,7 @@ bfd_elf_get_str_section (abfd, shindex) char * bfd_elf_string_from_elf_section (abfd, shindex, strindex) - bfd * abfd; + bfd *abfd; unsigned int shindex; unsigned int strindex; { @@ -155,9 +332,206 @@ bfd_elf_string_from_elf_section (abfd, shindex, strindex) && bfd_elf_get_str_section (abfd, shindex) == NULL) return NULL; + if (strindex >= hdr->sh_size) + { + (*_bfd_error_handler) + (_("%s: invalid string offset %u >= %lu for section `%s'"), + bfd_archive_filename (abfd), strindex, (unsigned long) hdr->sh_size, + ((shindex == elf_elfheader(abfd)->e_shstrndx + && strindex == hdr->sh_name) + ? ".shstrtab" + : elf_string_from_elf_strtab (abfd, hdr->sh_name))); + return ""; + } + return ((char *) hdr->contents) + strindex; } +/* Elf_Internal_Shdr->contents is an array of these for SHT_GROUP + sections. The first element is the flags, the rest are section + pointers. */ + +typedef union elf_internal_group { + Elf_Internal_Shdr *shdr; + unsigned int flags; +} Elf_Internal_Group; + +/* Set next_in_group list pointer, and group name for NEWSECT. */ + +static boolean +setup_group (abfd, hdr, newsect) + bfd *abfd; + Elf_Internal_Shdr *hdr; + asection *newsect; +{ + unsigned int num_group = elf_tdata (abfd)->num_group; + + /* If num_group is zero, read in all SHT_GROUP sections. The count + is set to -1 if there are no SHT_GROUP sections. */ + if (num_group == 0) + { + unsigned int i, shnum; + + /* First count the number of groups. If we have a SHT_GROUP + section with just a flag word (ie. sh_size is 4), ignore it. */ + shnum = elf_elfheader (abfd)->e_shnum; + num_group = 0; + for (i = 0; i < shnum; i++) + { + Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; + if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8) + num_group += 1; + } + + if (num_group == 0) + num_group = -1; + elf_tdata (abfd)->num_group = num_group; + + if (num_group > 0) + { + /* We keep a list of elf section headers for group sections, + so we can find them quickly. */ + bfd_size_type amt = num_group * sizeof (Elf_Internal_Shdr *); + elf_tdata (abfd)->group_sect_ptr = bfd_alloc (abfd, amt); + if (elf_tdata (abfd)->group_sect_ptr == NULL) + return false; + + num_group = 0; + for (i = 0; i < shnum; i++) + { + Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; + if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8) + { + char *src; + Elf_Internal_Group *dest; + + /* Add to list of sections. */ + elf_tdata (abfd)->group_sect_ptr[num_group] = shdr; + num_group += 1; + + /* Read the raw contents. */ + BFD_ASSERT (sizeof (*dest) >= 4); + amt = shdr->sh_size * sizeof (*dest) / 4; + shdr->contents = bfd_alloc (abfd, amt); + if (shdr->contents == NULL + || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0 + || (bfd_bread (shdr->contents, shdr->sh_size, abfd) + != shdr->sh_size)) + return false; + + /* Translate raw contents, a flag word followed by an + array of elf section indices all in target byte order, + to the flag word followed by an array of elf section + pointers. */ + src = shdr->contents + shdr->sh_size; + dest = (Elf_Internal_Group *) (shdr->contents + amt); + while (1) + { + unsigned int idx; + + src -= 4; + --dest; + idx = H_GET_32 (abfd, src); + if (src == shdr->contents) + { + dest->flags = idx; + break; + } + if (idx >= shnum) + { + ((*_bfd_error_handler) + (_("%s: invalid SHT_GROUP entry"), + bfd_archive_filename (abfd))); + idx = 0; + } + dest->shdr = elf_elfsections (abfd)[idx]; + } + } + } + } + } + + if (num_group != (unsigned) -1) + { + unsigned int i; + + for (i = 0; i < num_group; i++) + { + Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i]; + Elf_Internal_Group *idx = (Elf_Internal_Group *) shdr->contents; + unsigned int n_elt = shdr->sh_size / 4; + + /* Look through this group's sections to see if current + section is a member. */ + while (--n_elt != 0) + if ((++idx)->shdr == hdr) + { + asection *s; + + /* We are a member of this group. Go looking through + other members to see if any others are linked via + next_in_group. */ + idx = (Elf_Internal_Group *) shdr->contents; + n_elt = shdr->sh_size / 4; + while (--n_elt != 0) + if ((s = (++idx)->shdr->bfd_section) != NULL + && elf_section_data (s)->next_in_group != NULL) + break; + if (n_elt != 0) + { + const char *gname; + asection *next; + + /* Snarf the group name from other member, and + insert current section in circular list. */ + gname = elf_section_data (s)->group; + elf_section_data (newsect)->group = gname; + next = elf_section_data (s)->next_in_group; + elf_section_data (newsect)->next_in_group = next; + elf_section_data (s)->next_in_group = newsect; + } + else + { + struct elf_backend_data *bed; + file_ptr pos; + unsigned char ename[4]; + unsigned long iname; + const char *gname; + + /* Humbug. Get the name from the group signature + symbol. Why isn't the signature just a string? + Fortunately, the name index is at the same + place in the external symbol for both 32 and 64 + bit ELF. */ + bed = get_elf_backend_data (abfd); + pos = elf_tdata (abfd)->symtab_hdr.sh_offset; + pos += shdr->sh_info * bed->s->sizeof_sym; + if (bfd_seek (abfd, pos, SEEK_SET) != 0 + || bfd_bread (ename, 4, abfd) != 4) + return false; + iname = H_GET_32 (abfd, ename); + gname = elf_string_from_elf_strtab (abfd, iname); + elf_section_data (newsect)->group = gname; + + /* Start a circular list with one element. */ + elf_section_data (newsect)->next_in_group = newsect; + } + if (shdr->bfd_section != NULL) + shdr->bfd_section->lineno = (alent *) newsect; + i = num_group - 1; + break; + } + } + } + + if (elf_section_data (newsect)->group == NULL) + { + (*_bfd_error_handler) (_("%s: no group info for section %s"), + bfd_archive_filename (abfd), newsect->name); + } + return true; +} + /* Make a BFD section from an ELF section. We store a pointer to the BFD section in the bfd_section field of the header. */ @@ -169,6 +543,7 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name) { asection *newsect; flagword flags; + struct elf_backend_data *bed; if (hdr->bfd_section != NULL) { @@ -186,12 +561,14 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name) if (! bfd_set_section_vma (abfd, newsect, hdr->sh_addr) || ! bfd_set_section_size (abfd, newsect, hdr->sh_size) || ! bfd_set_section_alignment (abfd, newsect, - bfd_log2 (hdr->sh_addralign))) + bfd_log2 ((bfd_vma) hdr->sh_addralign))) return false; flags = SEC_NO_FLAGS; if (hdr->sh_type != SHT_NOBITS) flags |= SEC_HAS_CONTENTS; + if (hdr->sh_type == SHT_GROUP) + flags |= SEC_GROUP | SEC_EXCLUDE; if ((hdr->sh_flags & SHF_ALLOC) != 0) { flags |= SEC_ALLOC; @@ -204,13 +581,50 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name) flags |= SEC_CODE; else if ((flags & SEC_LOAD) != 0) flags |= SEC_DATA; + if ((hdr->sh_flags & SHF_MERGE) != 0) + { + flags |= SEC_MERGE; + newsect->entsize = hdr->sh_entsize; + if ((hdr->sh_flags & SHF_STRINGS) != 0) + flags |= SEC_STRINGS; + } + if (hdr->sh_flags & SHF_GROUP) + if (!setup_group (abfd, hdr, newsect)) + return false; /* The debugging sections appear to be recognized only by name, not any sort of flag. */ - if (strncmp (name, ".debug", sizeof ".debug" - 1) == 0 - || strncmp (name, ".line", sizeof ".line" - 1) == 0 - || strncmp (name, ".stab", sizeof ".stab" - 1) == 0) - flags |= SEC_DEBUGGING; + { + static const char *debug_sec_names [] = + { + ".debug", + ".gnu.linkonce.wi.", + ".line", + ".stab" + }; + int i; + + for (i = sizeof (debug_sec_names) / sizeof (debug_sec_names[0]); i--;) + if (strncmp (name, debug_sec_names[i], strlen (debug_sec_names[i])) == 0) + break; + + if (i >= 0) + flags |= SEC_DEBUGGING; + } + + /* As a GNU extension, if the name begins with .gnu.linkonce, we + only link a single copy of the section. This is used to support + g++. g++ will emit each template expansion in its own section. + The symbols will be defined as weak, so that multiple definitions + are permitted. The GNU linker extension is to actually discard + all but one of the sections. */ + if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0) + flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_section_flags) + if (! bed->elf_backend_section_flags (&flags, hdr)) + return false; if (! bfd_set_section_flags (abfd, newsect, flags)) return false; @@ -220,22 +634,33 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name) Elf_Internal_Phdr *phdr; unsigned int i; - /* Look through the phdrs to see if we need to adjust the lma. */ + /* Look through the phdrs to see if we need to adjust the lma. + If all the p_paddr fields are zero, we ignore them, since + some ELF linkers produce such output. */ phdr = elf_tdata (abfd)->phdr; for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) { - if (phdr->p_type == PT_LOAD - && phdr->p_paddr != 0 - && phdr->p_vaddr != phdr->p_paddr - && phdr->p_vaddr <= hdr->sh_addr - && phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size - && ((flags & SEC_LOAD) == 0 - || (phdr->p_offset <= hdr->sh_offset - && (phdr->p_offset + phdr->p_filesz - >= hdr->sh_offset + hdr->sh_size)))) + if (phdr->p_paddr != 0) + break; + } + if (i < elf_elfheader (abfd)->e_phnum) + { + phdr = elf_tdata (abfd)->phdr; + for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) { - newsect->lma += phdr->p_paddr - phdr->p_vaddr; - break; + if (phdr->p_type == PT_LOAD + && phdr->p_vaddr != phdr->p_paddr + && phdr->p_vaddr <= hdr->sh_addr + && (phdr->p_vaddr + phdr->p_memsz + >= hdr->sh_addr + hdr->sh_size) + && ((flags & SEC_LOAD) == 0 + || (phdr->p_offset <= (bfd_vma) hdr->sh_offset + && (phdr->p_offset + phdr->p_filesz + >= hdr->sh_offset + hdr->sh_size)))) + { + newsect->lma += phdr->p_paddr - phdr->p_vaddr; + break; + } } } } @@ -263,7 +688,7 @@ DESCRIPTION struct elf_internal_shdr * bfd_elf_find_section (abfd, name) - bfd * abfd; + bfd *abfd; char *name; { Elf_Internal_Shdr **i_shdrp; @@ -274,7 +699,8 @@ bfd_elf_find_section (abfd, name) i_shdrp = elf_elfsections (abfd); if (i_shdrp != NULL) { - shstrtab = bfd_elf_get_str_section (abfd, elf_elfheader (abfd)->e_shstrndx); + shstrtab = bfd_elf_get_str_section + (abfd, elf_elfheader (abfd)->e_shstrndx); if (shstrtab != NULL) { max = elf_elfheader (abfd)->e_shnum; @@ -302,7 +728,6 @@ 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, @@ -311,13 +736,13 @@ bfd_elf_generic_reloc (abfd, input_section, output_bfd, error_message) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; arelent *reloc_entry; asymbol *symbol; - PTR data; + PTR data ATTRIBUTE_UNUSED; asection *input_section; bfd *output_bfd; - char **error_message; + char **error_message ATTRIBUTE_UNUSED; { if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0 @@ -331,6 +756,20 @@ bfd_elf_generic_reloc (abfd, return bfd_reloc_continue; } +/* Finish SHF_MERGE section merging. */ + +boolean +_bfd_elf_merge_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + if (!is_elf_hash_table (info)) + return false; + if (elf_hash_table (info)->merge_info) + _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info); + return true; +} + /* Print out the program headers. */ boolean @@ -348,41 +787,41 @@ _bfd_elf_print_private_bfd_data (abfd, farg) { unsigned int i, c; - fprintf (f, "\nProgram Header:\n"); + fprintf (f, _("\nProgram Header:\n")); c = elf_elfheader (abfd)->e_phnum; for (i = 0; i < c; i++, p++) { - const char *s; + const char *pt; char buf[20]; switch (p->p_type) { - case PT_NULL: s = "NULL"; break; - case PT_LOAD: s = "LOAD"; break; - case PT_DYNAMIC: s = "DYNAMIC"; break; - case PT_INTERP: s = "INTERP"; break; - case PT_NOTE: s = "NOTE"; break; - case PT_SHLIB: s = "SHLIB"; break; - case PT_PHDR: s = "PHDR"; break; - default: sprintf (buf, "0x%lx", p->p_type); s = buf; break; + case PT_NULL: pt = "NULL"; break; + case PT_LOAD: pt = "LOAD"; break; + case PT_DYNAMIC: pt = "DYNAMIC"; break; + case PT_INTERP: pt = "INTERP"; break; + case PT_NOTE: pt = "NOTE"; break; + case PT_SHLIB: pt = "SHLIB"; break; + case PT_PHDR: pt = "PHDR"; break; + default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break; } - fprintf (f, "%8s off 0x", s); - fprintf_vma (f, p->p_offset); + fprintf (f, "%8s off 0x", pt); + bfd_fprintf_vma (abfd, f, p->p_offset); fprintf (f, " vaddr 0x"); - fprintf_vma (f, p->p_vaddr); + bfd_fprintf_vma (abfd, f, p->p_vaddr); fprintf (f, " paddr 0x"); - fprintf_vma (f, p->p_paddr); + bfd_fprintf_vma (abfd, f, p->p_paddr); fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align)); fprintf (f, " filesz 0x"); - fprintf_vma (f, p->p_filesz); + bfd_fprintf_vma (abfd, f, p->p_filesz); fprintf (f, " memsz 0x"); - fprintf_vma (f, p->p_memsz); + bfd_fprintf_vma (abfd, f, p->p_memsz); fprintf (f, " flags %c%c%c", (p->p_flags & PF_R) != 0 ? 'r' : '-', (p->p_flags & PF_W) != 0 ? 'w' : '-', (p->p_flags & PF_X) != 0 ? 'x' : '-'); - if ((p->p_flags &~ (PF_R | PF_W | PF_X)) != 0) - fprintf (f, " %lx", p->p_flags &~ (PF_R | PF_W | PF_X)); + if ((p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X)) != 0) + fprintf (f, " %lx", p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X)); fprintf (f, "\n"); } } @@ -391,12 +830,12 @@ _bfd_elf_print_private_bfd_data (abfd, farg) if (s != NULL) { int elfsec; - unsigned long link; + unsigned long shlink; bfd_byte *extdyn, *extdynend; size_t extdynsize; void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); - fprintf (f, "\nDynamic Section:\n"); + fprintf (f, _("\nDynamic Section:\n")); dynbuf = (bfd_byte *) bfd_malloc (s->_raw_size); if (dynbuf == NULL) @@ -408,7 +847,7 @@ _bfd_elf_print_private_bfd_data (abfd, farg) elfsec = _bfd_elf_section_from_bfd_section (abfd, s); if (elfsec == -1) goto error_return; - link = elf_elfsections (abfd)[elfsec]->sh_link; + shlink = elf_elfsections (abfd)[elfsec]->sh_link; extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; @@ -458,6 +897,40 @@ _bfd_elf_print_private_bfd_data (abfd, farg) case DT_DEBUG: name = "DEBUG"; break; case DT_TEXTREL: name = "TEXTREL"; break; case DT_JMPREL: name = "JMPREL"; break; + case DT_BIND_NOW: name = "BIND_NOW"; break; + case DT_INIT_ARRAY: name = "INIT_ARRAY"; break; + case DT_FINI_ARRAY: name = "FINI_ARRAY"; break; + case DT_INIT_ARRAYSZ: name = "INIT_ARRAYSZ"; break; + case DT_FINI_ARRAYSZ: name = "FINI_ARRAYSZ"; break; + case DT_RUNPATH: name = "RUNPATH"; stringp = true; break; + case DT_FLAGS: name = "FLAGS"; break; + case DT_PREINIT_ARRAY: name = "PREINIT_ARRAY"; break; + case DT_PREINIT_ARRAYSZ: name = "PREINIT_ARRAYSZ"; break; + case DT_CHECKSUM: name = "CHECKSUM"; break; + case DT_PLTPADSZ: name = "PLTPADSZ"; break; + case DT_MOVEENT: name = "MOVEENT"; break; + case DT_MOVESZ: name = "MOVESZ"; break; + case DT_FEATURE: name = "FEATURE"; break; + case DT_POSFLAG_1: name = "POSFLAG_1"; break; + case DT_SYMINSZ: name = "SYMINSZ"; break; + case DT_SYMINENT: name = "SYMINENT"; break; + case DT_CONFIG: name = "CONFIG"; stringp = true; break; + case DT_DEPAUDIT: name = "DEPAUDIT"; stringp = true; break; + case DT_AUDIT: name = "AUDIT"; stringp = true; break; + case DT_PLTPAD: name = "PLTPAD"; break; + case DT_MOVETAB: name = "MOVETAB"; break; + case DT_SYMINFO: name = "SYMINFO"; break; + case DT_RELACOUNT: name = "RELACOUNT"; break; + case DT_RELCOUNT: name = "RELCOUNT"; break; + case DT_FLAGS_1: name = "FLAGS_1"; break; + case DT_VERSYM: name = "VERSYM"; break; + case DT_VERDEF: name = "VERDEF"; break; + case DT_VERDEFNUM: name = "VERDEFNUM"; break; + case DT_VERNEED: name = "VERNEED"; break; + case DT_VERNEEDNUM: name = "VERNEEDNUM"; break; + case DT_AUXILIARY: name = "AUXILIARY"; stringp = true; break; + case DT_USED: name = "USED"; break; + case DT_FILTER: name = "FILTER"; stringp = true; break; } fprintf (f, " %-11s ", name); @@ -466,9 +939,9 @@ _bfd_elf_print_private_bfd_data (abfd, farg) else { const char *string; + unsigned int tagv = dyn.d_un.d_val; - string = bfd_elf_string_from_elf_section (abfd, link, - dyn.d_un.d_val); + string = bfd_elf_string_from_elf_section (abfd, shlink, tagv); if (string == NULL) goto error_return; fprintf (f, "%s", string); @@ -480,6 +953,52 @@ _bfd_elf_print_private_bfd_data (abfd, farg) dynbuf = NULL; } + if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL) + || (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL)) + { + if (! _bfd_elf_slurp_version_tables (abfd)) + return false; + } + + if (elf_dynverdef (abfd) != 0) + { + Elf_Internal_Verdef *t; + + fprintf (f, _("\nVersion definitions:\n")); + for (t = elf_tdata (abfd)->verdef; t != NULL; t = t->vd_nextdef) + { + fprintf (f, "%d 0x%2.2x 0x%8.8lx %s\n", t->vd_ndx, + t->vd_flags, t->vd_hash, t->vd_nodename); + if (t->vd_auxptr->vda_nextptr != NULL) + { + Elf_Internal_Verdaux *a; + + fprintf (f, "\t"); + for (a = t->vd_auxptr->vda_nextptr; + a != NULL; + a = a->vda_nextptr) + fprintf (f, "%s ", a->vda_nodename); + fprintf (f, "\n"); + } + } + } + + if (elf_dynverref (abfd) != 0) + { + Elf_Internal_Verneed *t; + + fprintf (f, _("\nVersion References:\n")); + for (t = elf_tdata (abfd)->verref; t != NULL; t = t->vn_nextref) + { + Elf_Internal_Vernaux *a; + + fprintf (f, _(" required from %s:\n"), t->vn_filename); + for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + fprintf (f, " 0x%8.8lx 0x%2.2x %2.2d %s\n", a->vna_hash, + a->vna_flags, a->vna_other, a->vna_nodename); + } + } + return true; error_return: @@ -489,9 +1008,10 @@ _bfd_elf_print_private_bfd_data (abfd, farg) } /* Display ELF-specific fields of a symbol. */ + void -bfd_elf_print_symbol (ignore_abfd, filep, symbol, how) - bfd *ignore_abfd; +bfd_elf_print_symbol (abfd, filep, symbol, how) + bfd *abfd; PTR filep; asymbol *symbol; bfd_print_symbol_type how; @@ -504,24 +1024,107 @@ bfd_elf_print_symbol (ignore_abfd, filep, symbol, how) break; case bfd_print_symbol_more: fprintf (file, "elf "); - fprintf_vma (file, symbol->value); + bfd_fprintf_vma (abfd, file, symbol->value); fprintf (file, " %lx", (long) symbol->flags); break; case bfd_print_symbol_all: { - CONST char *section_name; + const char *section_name; + const char *name = NULL; + struct elf_backend_data *bed; + unsigned char st_other; + bfd_vma val; + section_name = symbol->section ? symbol->section->name : "(*none*)"; - bfd_print_symbol_vandf ((PTR) file, symbol); + + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_print_symbol_all) + name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol); + + if (name == NULL) + { + name = symbol->name; + bfd_print_symbol_vandf (abfd, (PTR) file, symbol); + } + fprintf (file, " %s\t", section_name); /* Print the "other" value for a symbol. For common symbols, we've already printed the size; now print the alignment. For other symbols, we have no specified alignment, and we've printed the address; now print the size. */ - fprintf_vma (file, - (bfd_is_com_section (symbol->section) - ? ((elf_symbol_type *) symbol)->internal_elf_sym.st_value - : ((elf_symbol_type *) symbol)->internal_elf_sym.st_size)); - fprintf (file, " %s", symbol->name); + if (bfd_is_com_section (symbol->section)) + val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value; + else + val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_size; + bfd_fprintf_vma (abfd, file, val); + + /* If we have version information, print it. */ + if (elf_tdata (abfd)->dynversym_section != 0 + && (elf_tdata (abfd)->dynverdef_section != 0 + || elf_tdata (abfd)->dynverref_section != 0)) + { + unsigned int vernum; + const char *version_string; + + vernum = ((elf_symbol_type *) symbol)->version & VERSYM_VERSION; + + if (vernum == 0) + version_string = ""; + else if (vernum == 1) + version_string = "Base"; + else if (vernum <= elf_tdata (abfd)->cverdefs) + version_string = + elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; + else + { + Elf_Internal_Verneed *t; + + version_string = ""; + for (t = elf_tdata (abfd)->verref; + t != NULL; + t = t->vn_nextref) + { + Elf_Internal_Vernaux *a; + + for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + { + if (a->vna_other == vernum) + { + version_string = a->vna_nodename; + break; + } + } + } + } + + if ((((elf_symbol_type *) symbol)->version & VERSYM_HIDDEN) == 0) + fprintf (file, " %-11s", version_string); + else + { + int i; + + fprintf (file, " (%s)", version_string); + for (i = 10 - strlen (version_string); i > 0; --i) + putc (' ', file); + } + } + + /* If the st_other field is not zero, print it. */ + st_other = ((elf_symbol_type *) symbol)->internal_elf_sym.st_other; + + switch (st_other) + { + case 0: break; + case STV_INTERNAL: fprintf (file, " .internal"); break; + case STV_HIDDEN: fprintf (file, " .hidden"); break; + case STV_PROTECTED: fprintf (file, " .protected"); break; + default: + /* Some other non-defined flags are also present, so print + everything hex. */ + fprintf (file, " 0x%02x", (unsigned int) st_other); + } + + fprintf (file, " %s", name); } break; } @@ -535,32 +1138,37 @@ _bfd_elf_link_hash_newfunc (entry, table, string) 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) - return (struct bfd_hash_entry *) ret; + if (entry == NULL) + { + entry = bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)); + if (entry == NULL) + return entry; + } /* 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) + entry = _bfd_link_hash_newfunc (entry, table, string); + if (entry != NULL) { + struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry; + struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table; + /* Set local fields. */ ret->indx = -1; ret->size = 0; ret->dynindx = -1; ret->dynstr_index = 0; ret->weakdef = NULL; - ret->got_offset = (bfd_vma) -1; - ret->plt_offset = (bfd_vma) -1; - ret->linker_section_pointer = (elf_linker_section_pointers_t *)0; + ret->got.refcount = htab->init_refcount; + ret->plt.refcount = htab->init_refcount; + ret->linker_section_pointer = NULL; + ret->verinfo.verdef = NULL; + ret->vtable_entries_used = NULL; + ret->vtable_entries_size = 0; + ret->vtable_parent = NULL; ret->type = STT_NOTYPE; + ret->other = 0; /* Assume that we have been called by a non-ELF symbol reader. This flag is then reset by the code which reads an ELF input file. This ensures that a symbol created by a non-ELF symbol @@ -568,7 +1176,71 @@ _bfd_elf_link_hash_newfunc (entry, table, string) ret->elf_link_hash_flags = ELF_LINK_NON_ELF; } - return (struct bfd_hash_entry *) ret; + return entry; +} + +/* Copy data from an indirect symbol to its direct symbol, hiding the + old indirect symbol. Also used for copying flags to a weakdef. */ + +void +_bfd_elf_link_hash_copy_indirect (dir, ind) + struct elf_link_hash_entry *dir, *ind; +{ + bfd_signed_vma tmp; + + /* Copy down any references that we may have already seen to the + symbol which just became indirect. */ + + dir->elf_link_hash_flags |= + (ind->elf_link_hash_flags + & (ELF_LINK_HASH_REF_DYNAMIC + | ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_REF_REGULAR_NONWEAK + | ELF_LINK_NON_GOT_REF)); + + if (dir == ind->weakdef) + return; + + /* Copy over the global and procedure linkage table refcount entries. + These may have been already set up by a check_relocs routine. */ + tmp = dir->got.refcount; + if (tmp <= 0) + { + dir->got.refcount = ind->got.refcount; + ind->got.refcount = tmp; + } + else + BFD_ASSERT (ind->got.refcount <= 0); + + tmp = dir->plt.refcount; + if (tmp <= 0) + { + dir->plt.refcount = ind->plt.refcount; + ind->plt.refcount = tmp; + } + else + BFD_ASSERT (ind->plt.refcount <= 0); + + if (dir->dynindx == -1) + { + dir->dynindx = ind->dynindx; + dir->dynstr_index = ind->dynstr_index; + ind->dynindx = -1; + ind->dynstr_index = 0; + } + else + BFD_ASSERT (ind->dynindx == -1); +} + +void +_bfd_elf_link_hash_hide_symbol (info, h) + struct bfd_link_info *info ATTRIBUTE_UNUSED; + struct elf_link_hash_entry *h; +{ + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + h->plt.offset = (bfd_vma) -1; + if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) + h->dynindx = -1; } /* Initialize an ELF linker hash table. */ @@ -581,16 +1253,25 @@ _bfd_elf_link_hash_table_init (table, abfd, newfunc) struct bfd_hash_table *, const char *)); { + boolean ret; + table->dynamic_sections_created = false; table->dynobj = NULL; + table->init_refcount = get_elf_backend_data (abfd)->can_refcount - 1; /* The first dynamic symbol is a dummy. */ table->dynsymcount = 1; table->dynstr = NULL; table->bucketcount = 0; table->needed = NULL; + table->runpath = NULL; table->hgot = NULL; table->stab_info = NULL; - return _bfd_link_hash_table_init (&table->root, abfd, newfunc); + table->merge_info = NULL; + table->dynlocal = NULL; + ret = _bfd_link_hash_table_init (& table->root, abfd, newfunc); + table->root.type = bfd_link_elf_hash_table; + + return ret; } /* Create an ELF linker hash table. */ @@ -600,9 +1281,9 @@ _bfd_elf_link_hash_table_create (abfd) bfd *abfd; { struct elf_link_hash_table *ret; + bfd_size_type amt = sizeof (struct elf_link_hash_table); - ret = ((struct elf_link_hash_table *) - bfd_alloc (abfd, sizeof (struct elf_link_hash_table))); + ret = (struct elf_link_hash_table *) bfd_alloc (abfd, amt); if (ret == (struct elf_link_hash_table *) NULL) return NULL; @@ -630,12 +1311,22 @@ bfd_elf_set_dt_needed_name (abfd, name) elf_dt_name (abfd) = name; } +void +bfd_elf_set_dt_needed_soname (abfd, name) + bfd *abfd; + const char *name; +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + elf_dt_soname (abfd) = name; +} + /* Get the list of DT_NEEDED entries for a link. This is a hook for - the ELF emulation code. */ + the linker ELF emulation code. */ struct bfd_link_needed_list * bfd_elf_get_needed_list (abfd, info) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; struct bfd_link_info *info; { if (info->hash->creator->flavour != bfd_target_elf_flavour) @@ -643,6 +1334,19 @@ bfd_elf_get_needed_list (abfd, info) return elf_hash_table (info)->needed; } +/* Get the list of DT_RPATH/DT_RUNPATH entries for a link. This is a + hook for the linker ELF emulation code. */ + +struct bfd_link_needed_list * +bfd_elf_get_runpath_list (abfd, info) + bfd *abfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info; +{ + if (info->hash->creator->flavour != bfd_target_elf_flavour) + return NULL; + return elf_hash_table (info)->runpath; +} + /* Get the name actually used for a dynamic object for a link. This is the SONAME entry if there is one. Otherwise, it is the string passed to bfd_elf_set_dt_needed_name, or it is the filename. */ @@ -656,17 +1360,104 @@ bfd_elf_get_dt_soname (abfd) return elf_dt_name (abfd); return NULL; } - -/* Allocate an ELF string table--force the first byte to be zero. */ -struct bfd_strtab_hash * -_bfd_elf_stringtab_init () +/* Get the list of DT_NEEDED entries from a BFD. This is a hook for + the ELF linker emulation code. */ + +boolean +bfd_elf_get_bfd_needed_list (abfd, pneeded) + bfd *abfd; + struct bfd_link_needed_list **pneeded; { - struct bfd_strtab_hash *ret; + asection *s; + bfd_byte *dynbuf = NULL; + int elfsec; + unsigned long shlink; + bfd_byte *extdyn, *extdynend; + size_t extdynsize; + void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); - ret = _bfd_stringtab_init (); - if (ret != NULL) - { + *pneeded = NULL; + + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour + || bfd_get_format (abfd) != bfd_object) + return true; + + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s == NULL || s->_raw_size == 0) + return true; + + dynbuf = (bfd_byte *) bfd_malloc (s->_raw_size); + if (dynbuf == NULL) + goto error_return; + + if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf, (file_ptr) 0, + s->_raw_size)) + goto error_return; + + elfsec = _bfd_elf_section_from_bfd_section (abfd, s); + if (elfsec == -1) + goto error_return; + + shlink = elf_elfsections (abfd)[elfsec]->sh_link; + + extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; + swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; + + extdyn = dynbuf; + extdynend = extdyn + s->_raw_size; + for (; extdyn < extdynend; extdyn += extdynsize) + { + Elf_Internal_Dyn dyn; + + (*swap_dyn_in) (abfd, (PTR) extdyn, &dyn); + + if (dyn.d_tag == DT_NULL) + break; + + if (dyn.d_tag == DT_NEEDED) + { + const char *string; + struct bfd_link_needed_list *l; + unsigned int tagv = dyn.d_un.d_val; + bfd_size_type amt; + + string = bfd_elf_string_from_elf_section (abfd, shlink, tagv); + if (string == NULL) + goto error_return; + + amt = sizeof *l; + l = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); + if (l == NULL) + goto error_return; + + l->by = abfd; + l->name = string; + l->next = *pneeded; + *pneeded = l; + } + } + + free (dynbuf); + + return true; + + error_return: + if (dynbuf != NULL) + free (dynbuf); + return false; +} + +/* Allocate an ELF string table--force the first byte to be zero. */ + +struct bfd_strtab_hash * +_bfd_elf_stringtab_init () +{ + struct bfd_strtab_hash *ret; + + ret = _bfd_stringtab_init (); + if (ret != NULL) + { bfd_size_type loc; loc = _bfd_stringtab_add (ret, "", true, false); @@ -682,7 +1473,7 @@ _bfd_elf_stringtab_init () /* ELF .o/exec file reading */ -/* Create a new bfd section from an ELF section header. */ +/* Create a new bfd section from an ELF section header. */ boolean bfd_section_from_shdr (abfd, shindex) @@ -807,6 +1598,15 @@ bfd_section_from_shdr (abfd, shindex) asection *target_sect; Elf_Internal_Shdr *hdr2; + /* Check for a bogus link to avoid crashing. */ + if (hdr->sh_link >= ehdr->e_shnum) + { + ((*_bfd_error_handler) + (_("%s: invalid link %lu for reloc section %s (index %u)"), + bfd_archive_filename (abfd), hdr->sh_link, name, shindex)); + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + } + /* For some incomprehensible reason Oracle distributes libraries for Solaris in which some of the objects have bogus sh_link fields. It would be nice if we could just @@ -846,8 +1646,10 @@ bfd_section_from_shdr (abfd, shindex) /* If this reloc section does not use the main symbol table we don't treat it as a reloc section. BFD can't adequately represent such a section, so at least for now, we don't - try. We just present it as a normal section. */ - if (hdr->sh_link != elf_onesymtab (abfd)) + try. We just present it as a normal section. We also + can't use it as a reloc section if it points to the null + section. */ + if (hdr->sh_link != elf_onesymtab (abfd) || hdr->sh_info == SHN_UNDEF) return _bfd_elf_make_section_from_shdr (abfd, hdr, name); if (! bfd_section_from_shdr (abfd, hdr->sh_info)) @@ -861,24 +1663,69 @@ bfd_section_from_shdr (abfd, shindex) hdr2 = &elf_section_data (target_sect)->rel_hdr; else { + bfd_size_type amt; BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL); - hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2)); + amt = sizeof (*hdr2); + hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); elf_section_data (target_sect)->rel_hdr2 = hdr2; } *hdr2 = *hdr; elf_elfsections (abfd)[shindex] = hdr2; - target_sect->reloc_count += hdr->sh_size / hdr->sh_entsize; + target_sect->reloc_count += NUM_SHDR_ENTRIES (hdr); target_sect->flags |= SEC_RELOC; target_sect->relocation = NULL; target_sect->rel_filepos = hdr->sh_offset; + /* In the section to which the relocations apply, mark whether + its relocations are of the REL or RELA variety. */ + if (hdr->sh_size != 0) + elf_section_data (target_sect)->use_rela_p + = (hdr->sh_type == SHT_RELA); abfd->flags |= HAS_RELOC; return true; } break; + case SHT_GNU_verdef: + elf_dynverdef (abfd) = shindex; + elf_tdata (abfd)->dynverdef_hdr = *hdr; + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + break; + + case SHT_GNU_versym: + elf_dynversym (abfd) = shindex; + elf_tdata (abfd)->dynversym_hdr = *hdr; + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + break; + + case SHT_GNU_verneed: + elf_dynverref (abfd) = shindex; + elf_tdata (abfd)->dynverref_hdr = *hdr; + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + break; + case SHT_SHLIB: return true; + case SHT_GROUP: + /* Make a section for objcopy and relocatable links. */ + if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return false; + if (hdr->contents != NULL) + { + Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents; + unsigned int n_elt = hdr->sh_size / 4; + asection *s; + + while (--n_elt != 0) + if ((s = (++idx)->shdr->bfd_section) != NULL + && elf_section_data (s)->next_in_group != NULL) + { + hdr->bfd_section->lineno = (alent *) s; + break; + } + } + break; + default: /* Check for any processor-specific section types. */ { @@ -911,12 +1758,17 @@ _bfd_elf_new_section_hook (abfd, sec) asection *sec; { struct bfd_elf_section_data *sdata; + bfd_size_type amt = sizeof (*sdata); - sdata = (struct bfd_elf_section_data *) bfd_alloc (abfd, sizeof (*sdata)); + sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd, amt); if (!sdata) return false; sec->used_by_bfd = (PTR) sdata; - memset (sdata, 0, sizeof (*sdata)); + + /* Indicate whether or not this section should use RELA relocations. */ + sdata->use_rela_p + = get_elf_backend_data (abfd)->default_use_rela_p; + return true; } @@ -943,21 +1795,22 @@ _bfd_elf_new_section_hook (abfd, sec) */ boolean -bfd_section_from_phdr (abfd, hdr, index) +_bfd_elf_make_section_from_phdr (abfd, hdr, index, typename) bfd *abfd; Elf_Internal_Phdr *hdr; int index; + const char *typename; { asection *newsect; char *name; char namebuf[64]; int split; - split = ((hdr->p_memsz > 0) && - (hdr->p_filesz > 0) && - (hdr->p_memsz > hdr->p_filesz)); - sprintf (namebuf, split ? "segment%da" : "segment%d", index); - name = bfd_alloc (abfd, strlen (namebuf) + 1); + split = ((hdr->p_memsz > 0) + && (hdr->p_filesz > 0) + && (hdr->p_memsz > hdr->p_filesz)); + sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : ""); + name = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1); if (!name) return false; strcpy (name, namebuf); @@ -976,7 +1829,7 @@ bfd_section_from_phdr (abfd, hdr, index) if (hdr->p_flags & PF_X) { /* FIXME: all we known is that it has execute PERMISSION, - may be data. */ + may be data. */ newsect->flags |= SEC_CODE; } } @@ -987,8 +1840,8 @@ bfd_section_from_phdr (abfd, hdr, index) if (split) { - sprintf (namebuf, "segment%db", index); - name = bfd_alloc (abfd, strlen (namebuf) + 1); + sprintf (namebuf, "%s%db", typename, index); + name = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1); if (!name) return false; strcpy (name, namebuf); @@ -1011,9 +1864,91 @@ bfd_section_from_phdr (abfd, hdr, index) return true; } +boolean +bfd_section_from_phdr (abfd, hdr, index) + bfd *abfd; + Elf_Internal_Phdr *hdr; + int index; +{ + struct elf_backend_data *bed; + + switch (hdr->p_type) + { + case PT_NULL: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "null"); + + case PT_LOAD: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "load"); + + case PT_DYNAMIC: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "dynamic"); + + case PT_INTERP: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "interp"); + + case PT_NOTE: + if (! _bfd_elf_make_section_from_phdr (abfd, hdr, index, "note")) + return false; + if (! elfcore_read_notes (abfd, (file_ptr) hdr->p_offset, hdr->p_filesz)) + return false; + return true; + + case PT_SHLIB: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "shlib"); + + case PT_PHDR: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "phdr"); + + default: + /* Check for any processor-specific program segment types. + If no handler for them, default to making "segment" sections. */ + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_section_from_phdr) + return (*bed->elf_backend_section_from_phdr) (abfd, hdr, index); + else + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "segment"); + } +} + +/* Initialize REL_HDR, the section-header for new section, containing + relocations against ASECT. If USE_RELA_P is true, we use RELA + relocations; otherwise, we use REL relocations. */ + +boolean +_bfd_elf_init_reloc_shdr (abfd, rel_hdr, asect, use_rela_p) + bfd *abfd; + Elf_Internal_Shdr *rel_hdr; + asection *asect; + boolean use_rela_p; +{ + char *name; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_size_type amt = sizeof ".rela" + strlen (asect->name); + + name = bfd_alloc (abfd, amt); + if (name == NULL) + return false; + sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name); + rel_hdr->sh_name = + (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name, + true, false); + if (rel_hdr->sh_name == (unsigned int) -1) + return false; + rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL; + rel_hdr->sh_entsize = (use_rela_p + ? bed->s->sizeof_rela + : bed->s->sizeof_rel); + rel_hdr->sh_addralign = bed->s->file_align; + rel_hdr->sh_flags = 0; + rel_hdr->sh_addr = 0; + rel_hdr->sh_size = 0; + rel_hdr->sh_offset = 0; + + return true; +} + /* Set up an ELF internal section header for a section. */ -/*ARGSUSED*/ static void elf_fake_sections (abfd, asect, failedptrarg) bfd *abfd; @@ -1066,7 +2001,7 @@ elf_fake_sections (abfd, asect, failedptrarg) else if (strcmp (asect->name, ".hash") == 0) { this_hdr->sh_type = SHT_HASH; - this_hdr->sh_entsize = bed->s->arch_size / 8; + this_hdr->sh_entsize = bed->s->sizeof_hash_entry; } else if (strcmp (asect->name, ".dynsym") == 0) { @@ -1079,33 +2014,63 @@ elf_fake_sections (abfd, asect, failedptrarg) this_hdr->sh_entsize = bed->s->sizeof_dyn; } else if (strncmp (asect->name, ".rela", 5) == 0 - && get_elf_backend_data (abfd)->use_rela_p) + && get_elf_backend_data (abfd)->may_use_rela_p) { this_hdr->sh_type = SHT_RELA; this_hdr->sh_entsize = bed->s->sizeof_rela; } else if (strncmp (asect->name, ".rel", 4) == 0 - && ! get_elf_backend_data (abfd)->use_rela_p) + && get_elf_backend_data (abfd)->may_use_rel_p) { this_hdr->sh_type = SHT_REL; this_hdr->sh_entsize = bed->s->sizeof_rel; } - else if (strcmp (asect->name, ".note") == 0) + else if (strncmp (asect->name, ".note", 5) == 0) this_hdr->sh_type = SHT_NOTE; else if (strncmp (asect->name, ".stab", 5) == 0 && strcmp (asect->name + strlen (asect->name) - 3, "str") == 0) this_hdr->sh_type = SHT_STRTAB; + else if (strcmp (asect->name, ".gnu.version") == 0) + { + this_hdr->sh_type = SHT_GNU_versym; + this_hdr->sh_entsize = sizeof (Elf_External_Versym); + } + else if (strcmp (asect->name, ".gnu.version_d") == 0) + { + this_hdr->sh_type = SHT_GNU_verdef; + this_hdr->sh_entsize = 0; + /* objcopy or strip will copy over sh_info, but may not set + cverdefs. The linker will set cverdefs, but sh_info will be + zero. */ + if (this_hdr->sh_info == 0) + this_hdr->sh_info = elf_tdata (abfd)->cverdefs; + else + BFD_ASSERT (elf_tdata (abfd)->cverdefs == 0 + || this_hdr->sh_info == elf_tdata (abfd)->cverdefs); + } + else if (strcmp (asect->name, ".gnu.version_r") == 0) + { + this_hdr->sh_type = SHT_GNU_verneed; + this_hdr->sh_entsize = 0; + /* objcopy or strip will copy over sh_info, but may not set + cverrefs. The linker will set cverrefs, but sh_info will be + zero. */ + if (this_hdr->sh_info == 0) + this_hdr->sh_info = elf_tdata (abfd)->cverrefs; + else + BFD_ASSERT (elf_tdata (abfd)->cverrefs == 0 + || this_hdr->sh_info == elf_tdata (abfd)->cverrefs); + } + else if ((asect->flags & SEC_GROUP) != 0) + { + this_hdr->sh_type = SHT_GROUP; + this_hdr->sh_entsize = 4; + } else if ((asect->flags & SEC_ALLOC) != 0 - && (asect->flags & SEC_LOAD) != 0) - this_hdr->sh_type = SHT_PROGBITS; - else if ((asect->flags & SEC_ALLOC) != 0 - && ((asect->flags & SEC_LOAD) == 0)) + && ((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)) this_hdr->sh_type = SHT_NOBITS; else - { - /* Who knows? */ - this_hdr->sh_type = SHT_PROGBITS; - } + this_hdr->sh_type = SHT_PROGBITS; if ((asect->flags & SEC_ALLOC) != 0) this_hdr->sh_flags |= SHF_ALLOC; @@ -1113,49 +2078,106 @@ elf_fake_sections (abfd, asect, failedptrarg) this_hdr->sh_flags |= SHF_WRITE; if ((asect->flags & SEC_CODE) != 0) this_hdr->sh_flags |= SHF_EXECINSTR; + if ((asect->flags & SEC_MERGE) != 0) + { + this_hdr->sh_flags |= SHF_MERGE; + this_hdr->sh_entsize = asect->entsize; + if ((asect->flags & SEC_STRINGS) != 0) + this_hdr->sh_flags |= SHF_STRINGS; + } + if (elf_section_data (asect)->group != NULL) + this_hdr->sh_flags |= SHF_GROUP; /* Check for processor-specific section types. */ - { - struct elf_backend_data *bed = get_elf_backend_data (abfd); - - if (bed->elf_backend_fake_sections) - (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect); - } + if (bed->elf_backend_fake_sections) + (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect); /* If the section has relocs, set up a section header for the - SHT_REL[A] section. */ - if ((asect->flags & SEC_RELOC) != 0) - { - Elf_Internal_Shdr *rela_hdr; - int use_rela_p = get_elf_backend_data (abfd)->use_rela_p; - char *name; + SHT_REL[A] section. If two relocation sections are required for + this section, it is up to the processor-specific back-end to + create the other. */ + if ((asect->flags & SEC_RELOC) != 0 + && !_bfd_elf_init_reloc_shdr (abfd, + &elf_section_data (asect)->rel_hdr, + asect, + elf_section_data (asect)->use_rela_p)) + *failedptr = true; +} - rela_hdr = &elf_section_data (asect)->rel_hdr; - name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name)); - if (name == NULL) +/* Fill in the contents of a SHT_GROUP section. */ + +static void +set_group_contents (abfd, sec, failedptrarg) + bfd *abfd; + asection *sec; + PTR failedptrarg ATTRIBUTE_UNUSED; +{ + boolean *failedptr = (boolean *) failedptrarg; + unsigned long symindx; + asection *elt; + unsigned char *loc; + struct bfd_link_order *l; + + if (elf_section_data (sec)->this_hdr.sh_type != SHT_GROUP + || *failedptr) + return; + + /* If called from the assembler, swap_out_syms will have set up + udata.i; If called for "ld -r", the symbols won't yet be mapped, + so emulate elf_bfd_final_link. */ + symindx = sec->symbol->udata.i; + if (symindx == 0) + symindx = elf_section_data (sec)->this_idx; + elf_section_data (sec)->this_hdr.sh_info = symindx; + + /* Nor will the contents be allocated for "ld -r". */ + if (sec->contents == NULL) + { + sec->contents = bfd_alloc (abfd, sec->_raw_size); + if (sec->contents == NULL) { *failedptr = true; return; } - sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name); - rela_hdr->sh_name = - (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name, - true, false); - if (rela_hdr->sh_name == (unsigned int) -1) + } + + loc = sec->contents + sec->_raw_size; + + /* Get the pointer to the first section in the group that we + squirreled away here. */ + elt = (asection *) sec->lineno; + + /* First element is a flag word. Rest of section is elf section + indices for all the sections of the group. Write them backwards + just to keep the group in the same order as given in .section + directives, not that it matters. */ + while (elt != NULL) + { + loc -= 4; + H_PUT_32 (abfd, elf_section_data (elt)->this_idx, loc); + elt = elf_section_data (elt)->next_in_group; + } + + /* If this is a relocatable link, then the above did nothing because + SEC is the output section. Look through the input sections + instead. */ + for (l = sec->link_order_head; l != NULL; l = l->next) + if (l->type == bfd_indirect_link_order + && (elt = (asection *) l->u.indirect.section->lineno) != NULL) + do { - *failedptr = true; - return; + loc -= 4; + H_PUT_32 (abfd, + elf_section_data (elt->output_section)->this_idx, loc); + elt = elf_section_data (elt)->next_in_group; + /* During a relocatable link, the lists are circular. */ } - rela_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL; - rela_hdr->sh_entsize = (use_rela_p - ? bed->s->sizeof_rela - : bed->s->sizeof_rel); - rela_hdr->sh_addralign = bed->s->file_align; - rela_hdr->sh_flags = 0; - rela_hdr->sh_addr = 0; - rela_hdr->sh_size = 0; - rela_hdr->sh_offset = 0; - } + while (elt != (asection *) l->u.indirect.section->lineno); + + loc -= 4; + H_PUT_32 (abfd, 0, loc); + + BFD_ASSERT (loc == sec->contents); } /* Assign all ELF section numbers. The dummy first section is handled here @@ -1170,7 +2192,7 @@ assign_section_numbers (abfd) asection *sec; unsigned int section_number; Elf_Internal_Shdr **i_shdrp; - struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_size_type amt; section_number = 1; @@ -1183,13 +2205,18 @@ assign_section_numbers (abfd) d->rel_idx = 0; else d->rel_idx = section_number++; + + if (d->rel_hdr2) + d->rel_idx2 = section_number++; + else + d->rel_idx2 = 0; } t->shstrtab_section = section_number++; elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section; t->shstrtab_hdr.sh_size = _bfd_stringtab_size (elf_shstrtab (abfd)); - if (abfd->symcount > 0) + if (bfd_get_symcount (abfd) > 0) { t->symtab_section = section_number++; t->strtab_section = section_number++; @@ -1199,13 +2226,13 @@ assign_section_numbers (abfd) /* Set up the list of section header pointers, in agreement with the indices. */ - i_shdrp = ((Elf_Internal_Shdr **) - bfd_alloc (abfd, section_number * sizeof (Elf_Internal_Shdr *))); + amt = section_number * sizeof (Elf_Internal_Shdr *); + i_shdrp = (Elf_Internal_Shdr **) bfd_alloc (abfd, amt); if (i_shdrp == NULL) return false; - i_shdrp[0] = ((Elf_Internal_Shdr *) - bfd_alloc (abfd, sizeof (Elf_Internal_Shdr))); + amt = sizeof (Elf_Internal_Shdr); + i_shdrp[0] = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); if (i_shdrp[0] == NULL) { bfd_release (abfd, i_shdrp); @@ -1216,7 +2243,7 @@ assign_section_numbers (abfd) elf_elfsections (abfd) = i_shdrp; i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr; - if (abfd->symcount > 0) + if (bfd_get_symcount (abfd) > 0) { i_shdrp[t->symtab_section] = &t->symtab_hdr; i_shdrp[t->strtab_section] = &t->strtab_hdr; @@ -1231,6 +2258,8 @@ assign_section_numbers (abfd) i_shdrp[d->this_idx] = &d->this_hdr; if (d->rel_idx != 0) i_shdrp[d->rel_idx] = &d->rel_hdr; + if (d->rel_idx2 != 0) + i_shdrp[d->rel_idx2] = d->rel_hdr2; /* Fill in the sh_link and sh_info fields while we're at it. */ @@ -1242,6 +2271,11 @@ assign_section_numbers (abfd) d->rel_hdr.sh_link = t->symtab_section; d->rel_hdr.sh_info = d->this_idx; } + if (d->rel_idx2 != 0) + { + d->rel_hdr2->sh_link = t->symtab_section; + d->rel_hdr2->sh_info = d->this_idx; + } switch (d->this_hdr.sh_type) { @@ -1280,7 +2314,7 @@ assign_section_numbers (abfd) char *alc; len = strlen (sec->name); - alc = (char *) bfd_malloc (len - 2); + alc = (char *) bfd_malloc ((bfd_size_type) len - 2); if (alc == NULL) return false; strncpy (alc, sec->name, len - 3); @@ -1293,27 +2327,34 @@ assign_section_numbers (abfd) /* This is a .stab section. */ elf_section_data (s)->this_hdr.sh_entsize = - 4 + 2 * (bed->s->arch_size / 8); + 4 + 2 * bfd_get_arch_size (abfd) / 8; } } break; case SHT_DYNAMIC: case SHT_DYNSYM: + case SHT_GNU_verneed: + case SHT_GNU_verdef: /* sh_link is the section header index of the string table - used for the dynamic entries or symbol table. */ + used for the dynamic entries, or the symbol table, or the + version strings. */ s = bfd_get_section_by_name (abfd, ".dynstr"); if (s != NULL) d->this_hdr.sh_link = elf_section_data (s)->this_idx; break; case SHT_HASH: + case SHT_GNU_versym: /* sh_link is the section header index of the symbol table - this hash table is for. */ + this hash table or version table is for. */ s = bfd_get_section_by_name (abfd, ".dynsym"); if (s != NULL) d->this_hdr.sh_link = elf_section_data (s)->this_idx; break; + + case SHT_GROUP: + d->this_hdr.sh_link = t->symtab_section; } } @@ -1342,18 +2383,19 @@ static boolean elf_map_symbols (abfd) bfd *abfd; { - int symcount = bfd_get_symcount (abfd); + unsigned int symcount = bfd_get_symcount (abfd); asymbol **syms = bfd_get_outsymbols (abfd); asymbol **sect_syms; - int num_locals = 0; - int num_globals = 0; - int num_locals2 = 0; - int num_globals2 = 0; + unsigned int num_locals = 0; + unsigned int num_globals = 0; + unsigned int num_locals2 = 0; + unsigned int num_globals2 = 0; int max_index = 0; - int num_sections = 0; - int idx; + unsigned int num_sections = 0; + unsigned int idx; asection *asect; asymbol **new_syms; + bfd_size_type amt; #ifdef DEBUG fprintf (stderr, "elf_map_symbols\n"); @@ -1369,26 +2411,45 @@ elf_map_symbols (abfd) } max_index++; - sect_syms = (asymbol **) bfd_zalloc (abfd, max_index * sizeof (asymbol *)); + amt = max_index * sizeof (asymbol *); + sect_syms = (asymbol **) bfd_zalloc (abfd, amt); if (sect_syms == NULL) return false; elf_section_syms (abfd) = sect_syms; + elf_num_section_syms (abfd) = max_index; for (idx = 0; idx < symcount; idx++) { - if ((syms[idx]->flags & BSF_SECTION_SYM) != 0 - && (syms[idx]->value + syms[idx]->section->vma) == 0) + asymbol *sym = syms[idx]; + + if ((sym->flags & BSF_SECTION_SYM) != 0 + && sym->value == 0) { asection *sec; - sec = syms[idx]->section; + sec = sym->section; + if (sec->owner != NULL) { if (sec->owner != abfd) { if (sec->output_offset != 0) continue; + sec = sec->output_section; + + /* Empty sections in the input files may have had a section + symbol created for them. (See the comment near the end of + _bfd_generic_link_output_symbols in linker.c). If the linker + script discards such sections then we will reach this point. + Since we know that we cannot avoid this case, we detect it + and skip the abort and the assignment to the sect_syms array. + To reproduce this particular case try running the linker + testsuite test ld-scripts/weak.exp for an ELF port that uses + the generic linker. */ + if (sec->owner == NULL) + continue; + BFD_ASSERT (sec->owner == abfd); } sect_syms[sec->index] = syms[idx]; @@ -1416,7 +2477,7 @@ elf_map_symbols (abfd) num_sections++; #ifdef DEBUG fprintf (stderr, - "creating section symbol, name = %s, value = 0x%.8lx, index = %d, section = 0x%.8lx\n", + _("creating section symbol, name = %s, value = 0x%.8lx, index = %d, section = 0x%.8lx\n"), asect->name, (long) asect->vma, asect->index, (long) asect); #endif } @@ -1444,16 +2505,16 @@ elf_map_symbols (abfd) } /* Now sort the symbols so the local symbols are first. */ - new_syms = ((asymbol **) - bfd_alloc (abfd, - (num_locals + num_globals) * sizeof (asymbol *))); + amt = (num_locals + num_globals) * sizeof (asymbol *); + new_syms = (asymbol **) bfd_alloc (abfd, amt); + if (new_syms == NULL) return false; for (idx = 0; idx < symcount; idx++) { asymbol *sym = syms[idx]; - int i; + unsigned int i; if (!sym_is_global (abfd, sym)) i = num_locals2++; @@ -1468,7 +2529,7 @@ elf_map_symbols (abfd) && sect_syms[asect->index]->flags == 0) { asymbol *sym = sect_syms[asect->index]; - int i; + unsigned int i; sym->flags = BSF_SECTION_SYM; if (!sym_is_global (abfd, sym)) @@ -1548,6 +2609,10 @@ _bfd_elf_compute_section_file_positions (abfd, link_info) if (! prep_headers (abfd)) return false; + /* Post process the headers if necessary. */ + if (bed->elf_backend_post_process_headers) + (*bed->elf_backend_post_process_headers) (abfd, link_info); + failed = false; bfd_map_over_sections (abfd, elf_fake_sections, &failed); if (failed) @@ -1557,9 +2622,19 @@ _bfd_elf_compute_section_file_positions (abfd, link_info) return false; /* The backend linker builds symbol table information itself. */ - if (link_info == NULL && abfd->symcount > 0) + if (link_info == NULL && bfd_get_symcount (abfd) > 0) { - if (! swap_out_syms (abfd, &strtab)) + /* Non-zero if doing a relocatable link. */ + int relocatable_p = ! (abfd->flags & (EXEC_P | DYNAMIC)); + + if (! swap_out_syms (abfd, &strtab, relocatable_p)) + return false; + } + + if (link_info == NULL || link_info->relocateable) + { + bfd_map_over_sections (abfd, set_group_contents, &failed); + if (failed) return false; } @@ -1578,7 +2653,7 @@ _bfd_elf_compute_section_file_positions (abfd, link_info) if (!assign_file_positions_except_relocs (abfd)) return false; - if (link_info == NULL && abfd->symcount > 0) + if (link_info == NULL && bfd_get_symcount (abfd) > 0) { file_ptr off; Elf_Internal_Shdr *hdr; @@ -1619,11 +2694,11 @@ make_mapping (abfd, sections, from, to, phdr) struct elf_segment_map *m; unsigned int i; asection **hdrpp; + bfd_size_type amt; - m = ((struct elf_segment_map *) - bfd_zalloc (abfd, - (sizeof (struct elf_segment_map) - + (to - from - 1) * sizeof (asection *)))); + amt = sizeof (struct elf_segment_map); + amt += (to - from - 1) * sizeof (asection *); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) return NULL; m->next = NULL; @@ -1659,9 +2734,10 @@ map_sections_to_segments (abfd) unsigned int phdr_index; bfd_vma maxpagesize; asection **hdrpp; - boolean phdr_in_section = true; + boolean phdr_in_segment = true; boolean writable; asection *dynsec; + bfd_size_type amt; if (elf_tdata (abfd)->segment_map != NULL) return true; @@ -1671,8 +2747,8 @@ map_sections_to_segments (abfd) /* Select the allocated sections, and sort them. */ - sections = (asection **) bfd_malloc (bfd_count_sections (abfd) - * sizeof (asection *)); + amt = bfd_count_sections (abfd) * sizeof (asection *); + sections = (asection **) bfd_malloc (amt); if (sections == NULL) goto error_return; @@ -1701,8 +2777,8 @@ map_sections_to_segments (abfd) s = bfd_get_section_by_name (abfd, ".interp"); if (s != NULL && (s->flags & SEC_LOAD) != 0) { - m = ((struct elf_segment_map *) - bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + amt = sizeof (struct elf_segment_map); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; @@ -1715,8 +2791,8 @@ map_sections_to_segments (abfd) *pm = m; pm = &m->next; - m = ((struct elf_segment_map *) - bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + amt = sizeof (struct elf_segment_map); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; @@ -1752,8 +2828,9 @@ map_sections_to_segments (abfd) if (phdr_size == 0) phdr_size = get_elf_backend_data (abfd)->s->sizeof_phdr; if ((abfd->flags & D_PAGED) == 0 + || sections[0]->lma < phdr_size || sections[0]->lma % maxpagesize < phdr_size % maxpagesize) - phdr_in_section = false; + phdr_in_segment = false; } for (i = 0, hdrpp = sections; i < count; i++, hdrpp++) @@ -1779,15 +2856,8 @@ map_sections_to_segments (abfd) segment. */ new_segment = true; } - else if ((abfd->flags & D_PAGED) == 0) - { - /* If the file is not demand paged, which means that we - don't require the sections to be correctly aligned in the - file, then there is no other reason for a new segment. */ - new_segment = false; - } else if (BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize) - < hdr->lma) + < BFD_ALIGN (hdr->lma, maxpagesize)) { /* If putting this section in this segment would force us to skip a page in the segment, then we need a new segment. */ @@ -1800,6 +2870,13 @@ map_sections_to_segments (abfd) nonloadable section in the same segment. */ new_segment = true; } + else if ((abfd->flags & D_PAGED) == 0) + { + /* If the file is not demand paged, which means that we + don't require the sections to be correctly aligned in the + file, then there is no other reason for a new segment. */ + new_segment = false; + } else if (! writable && (hdr->flags & SEC_READONLY) == 0 && (BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize) @@ -1831,7 +2908,7 @@ map_sections_to_segments (abfd) /* We need a new program segment. We must create a new program header holding all the sections from phdr_index until hdr. */ - m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section); + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); if (m == NULL) goto error_return; @@ -1845,13 +2922,13 @@ map_sections_to_segments (abfd) last_hdr = hdr; phdr_index = i; - phdr_in_section = false; + phdr_in_segment = false; } /* Create a final PT_LOAD program segment. */ if (last_hdr != NULL) { - m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section); + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); if (m == NULL) goto error_return; @@ -1862,8 +2939,8 @@ map_sections_to_segments (abfd) /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ if (dynsec != NULL) { - m = ((struct elf_segment_map *) - bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + amt = sizeof (struct elf_segment_map); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; @@ -1875,6 +2952,30 @@ map_sections_to_segments (abfd) pm = &m->next; } + /* For each loadable .note section, add a PT_NOTE segment. We don't + use bfd_get_section_by_name, because if we link together + nonloadable .note sections and loadable .note sections, we will + generate two .note sections in the output file. FIXME: Using + names for section types is bogus anyhow. */ + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LOAD) != 0 + && strncmp (s->name, ".note", 5) == 0) + { + amt = sizeof (struct elf_segment_map); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_NOTE; + m->count = 1; + m->sections[0] = s; + + *pm = m; + pm = &m->next; + } + } + free (sections); sections = NULL; @@ -1887,7 +2988,7 @@ map_sections_to_segments (abfd) return false; } -/* Sort sections by VMA. */ +/* Sort sections by address. */ static int elf_sort_sections (arg1, arg2) @@ -1897,16 +2998,18 @@ elf_sort_sections (arg1, arg2) const asection *sec1 = *(const asection **) arg1; const asection *sec2 = *(const asection **) arg2; - if (sec1->vma < sec2->vma) + /* Sort by LMA first, since this is the address used to + place the section into a segment. */ + if (sec1->lma < sec2->lma) return -1; - else if (sec1->vma > sec2->vma) + else if (sec1->lma > sec2->lma) return 1; - /* Sort by LMA. Normally the LMA and the VMA will be the same, and - this will do nothing. */ - if (sec1->lma < sec2->lma) + /* Then sort by VMA. Normally the LMA and the VMA will be + the same, and this will do nothing. */ + if (sec1->vma < sec2->vma) return -1; - else if (sec1->lma > sec2->lma) + else if (sec1->vma > sec2->vma) return 1; /* Put !SEC_LOAD sections after SEC_LOAD ones. */ @@ -1914,18 +3017,24 @@ elf_sort_sections (arg1, arg2) #define TOEND(x) (((x)->flags & SEC_LOAD) == 0) if (TOEND (sec1)) - if (TOEND (sec2)) - return sec1->target_index - sec2->target_index; - else - return 1; - - if (TOEND (sec2)) + { + if (TOEND (sec2)) + { + /* If the indicies are the same, do not return 0 + here, but continue to try the next comparison. */ + if (sec1->target_index - sec2->target_index != 0) + return sec1->target_index - sec2->target_index; + } + else + return 1; + } + else if (TOEND (sec2)) return -1; #undef TOEND - /* Sort by size, to put zero sized sections before others at the - same address. */ + /* Sort by size, to put zero sized sections + before others at the same address. */ if (sec1->_raw_size < sec2->_raw_size) return -1; @@ -1952,6 +3061,7 @@ assign_file_positions_for_segments (abfd) bfd_vma filehdr_vaddr, filehdr_paddr; bfd_vma phdrs_vaddr, phdrs_paddr; Elf_Internal_Phdr *p; + bfd_size_type amt; if (elf_tdata (abfd)->segment_map == NULL) { @@ -1983,7 +3093,7 @@ assign_file_positions_for_segments (abfd) if (alloc != 0 && count > alloc) { ((*_bfd_error_handler) - ("%s: Not enough room for program headers (allocated %u, need %u)", + (_("%s: Not enough room for program headers (allocated %u, need %u)"), bfd_get_filename (abfd), alloc, count)); bfd_set_error (bfd_error_bad_value); return false; @@ -1992,8 +3102,8 @@ assign_file_positions_for_segments (abfd) if (alloc == 0) alloc = count; - phdrs = ((Elf_Internal_Phdr *) - bfd_alloc (abfd, alloc * sizeof (Elf_Internal_Phdr))); + amt = alloc * sizeof (Elf_Internal_Phdr); + phdrs = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt); if (phdrs == NULL) return false; @@ -2004,6 +3114,7 @@ assign_file_positions_for_segments (abfd) filehdr_paddr = 0; phdrs_vaddr = 0; phdrs_paddr = 0; + for (m = elf_tdata (abfd)->segment_map, p = phdrs; m != NULL; m = m->next, p++) @@ -2018,21 +3129,30 @@ assign_file_positions_for_segments (abfd) elf_sort_sections); p->p_type = m->p_type; - - if (m->p_flags_valid) - p->p_flags = m->p_flags; - else - p->p_flags = 0; + p->p_flags = m->p_flags; if (p->p_type == PT_LOAD && m->count > 0 - && (m->sections[0]->flags & SEC_LOAD) != 0) + && (m->sections[0]->flags & SEC_ALLOC) != 0) { if ((abfd->flags & D_PAGED) != 0) off += (m->sections[0]->vma - off) % bed->maxpagesize; else - off += ((m->sections[0]->vma - off) - % (1 << bfd_get_section_alignment (abfd, m->sections[0]))); + { + bfd_size_type align; + + align = 0; + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) + { + bfd_size_type secalign; + + secalign = bfd_get_section_alignment (abfd, *secpp); + if (secalign > align) + align = secalign; + } + + off += (m->sections[0]->vma - off) % (1 << align); + } } if (m->count == 0) @@ -2069,6 +3189,15 @@ assign_file_positions_for_segments (abfd) if (m->count > 0) { BFD_ASSERT (p->p_type == PT_LOAD); + + if (p->p_vaddr < (bfd_vma) off) + { + _bfd_error_handler (_("%s: Not enough room for program headers, try linking with -N"), + bfd_get_filename (abfd)); + bfd_set_error (bfd_error_bad_value); + return false; + } + p->p_vaddr -= off; if (! m->p_paddr_valid) p->p_paddr -= off; @@ -2084,6 +3213,7 @@ assign_file_positions_for_segments (abfd) { if (! m->p_flags_valid) p->p_flags |= PF_R; + if (m->includes_filehdr) { if (p->p_type == PT_LOAD) @@ -2095,6 +3225,7 @@ assign_file_positions_for_segments (abfd) else { p->p_offset = bed->s->sizeof_ehdr; + if (m->count > 0) { BFD_ASSERT (p->p_type == PT_LOAD); @@ -2102,17 +3233,22 @@ assign_file_positions_for_segments (abfd) if (! m->p_paddr_valid) p->p_paddr -= off - p->p_offset; } + if (p->p_type == PT_LOAD) { phdrs_vaddr = p->p_vaddr; phdrs_paddr = p->p_paddr; } + else + phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr; } + p->p_filesz += alloc * bed->s->sizeof_phdr; p->p_memsz += alloc * bed->s->sizeof_phdr; } - if (p->p_type == PT_LOAD) + if (p->p_type == PT_LOAD + || (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)) { if (! m->includes_filehdr && ! m->includes_phdrs) p->p_offset = off; @@ -2127,6 +3263,7 @@ assign_file_positions_for_segments (abfd) } voff = off; + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) { asection *sec; @@ -2137,45 +3274,111 @@ assign_file_positions_for_segments (abfd) flags = sec->flags; align = 1 << bfd_get_section_alignment (abfd, sec); + /* The section may have artificial alignment forced by a + link script. Notice this case by the gap between the + cumulative phdr vma and the section's vma. */ + if (p->p_vaddr + p->p_memsz < sec->vma) + { + bfd_vma adjust = sec->vma - (p->p_vaddr + p->p_memsz); + + p->p_memsz += adjust; + off += adjust; + voff += adjust; + if ((flags & SEC_LOAD) != 0) + p->p_filesz += adjust; + } + if (p->p_type == PT_LOAD) { - bfd_vma adjust; + bfd_signed_vma adjust; - /* The section VMA must equal the file position modulo - the page size. */ - if ((flags & SEC_ALLOC) != 0) + if ((flags & SEC_LOAD) != 0) + { + adjust = sec->lma - (p->p_paddr + p->p_memsz); + if (adjust < 0) + adjust = 0; + } + else if ((flags & SEC_ALLOC) != 0) { + /* The section VMA must equal the file position + modulo the page size. FIXME: I'm not sure if + this adjustment is really necessary. We used to + not have the SEC_LOAD case just above, and then + this was necessary, but now I'm not sure. */ if ((abfd->flags & D_PAGED) != 0) adjust = (sec->vma - voff) % bed->maxpagesize; else adjust = (sec->vma - voff) % align; - if (adjust != 0) + } + else + adjust = 0; + + if (adjust != 0) + { + if (i == 0) { - if (i == 0) - abort (); - p->p_memsz += adjust; - off += adjust; - voff += adjust; - if ((flags & SEC_LOAD) != 0) - p->p_filesz += adjust; + (* _bfd_error_handler) + (_("Error: First section in segment (%s) starts at 0x%x"), + bfd_section_name (abfd, sec), sec->lma); + (* _bfd_error_handler) + (_(" whereas segment starts at 0x%x"), + p->p_paddr); + + return false; } + p->p_memsz += adjust; + off += adjust; + voff += adjust; + if ((flags & SEC_LOAD) != 0) + p->p_filesz += adjust; } sec->filepos = off; - if ((flags & SEC_LOAD) != 0) + /* We check SEC_HAS_CONTENTS here because if NOLOAD is + used in a linker script we may have a section with + SEC_LOAD clear but which is supposed to have + contents. */ + if ((flags & SEC_LOAD) != 0 + || (flags & SEC_HAS_CONTENTS) != 0) off += sec->_raw_size; + if ((flags & SEC_ALLOC) != 0) voff += sec->_raw_size; } - p->p_memsz += sec->_raw_size; + if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core) + { + /* The actual "note" segment has i == 0. + This is the one that actually contains everything. */ + if (i == 0) + { + sec->filepos = off; + p->p_filesz = sec->_raw_size; + off += sec->_raw_size; + voff = off; + } + else + { + /* Fake sections -- don't need to be written. */ + sec->filepos = 0; + sec->_raw_size = 0; + flags = sec->flags = 0; + } + p->p_memsz = 0; + p->p_align = 1; + } + else + { + p->p_memsz += sec->_raw_size; - if ((flags & SEC_LOAD) != 0) - p->p_filesz += sec->_raw_size; + if ((flags & SEC_LOAD) != 0) + p->p_filesz += sec->_raw_size; - if (align > p->p_align) - p->p_align = align; + if (align > p->p_align + && (p->p_type != PT_LOAD || (abfd->flags & D_PAGED) == 0)) + p->p_align = align; + } if (! m->p_flags_valid) { @@ -2228,7 +3431,7 @@ assign_file_positions_for_segments (abfd) elf_tdata (abfd)->next_file_pos = off; /* Write out the program headers. */ - if (bfd_seek (abfd, bed->s->sizeof_ehdr, SEEK_SET) != 0 + if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 || bed->s->write_out_phdrs (abfd, phdrs, alloc) != 0) return false; @@ -2289,6 +3492,16 @@ get_program_header_size (abfd) ++segs; } + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LOAD) != 0 + && strncmp (s->name, ".note", 5) == 0) + { + /* We need a PT_NOTE segment. */ + ++segs; + } + } + /* Let the backend count up any program headers it might need. */ if (bed->elf_backend_additional_program_headers) { @@ -2325,7 +3538,8 @@ assign_file_positions_except_relocs (abfd) file_ptr off; struct elf_backend_data *bed = get_elf_backend_data (abfd); - if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 + && bfd_get_format (abfd) != bfd_core) { Elf_Internal_Shdr **hdrpp; unsigned int i; @@ -2352,7 +3566,7 @@ assign_file_positions_except_relocs (abfd) hdr->sh_offset = -1; continue; } - + off = _bfd_elf_assign_file_position_for_section (hdr, off, true); } } @@ -2380,7 +3594,7 @@ assign_file_positions_except_relocs (abfd) else if ((hdr->sh_flags & SHF_ALLOC) != 0) { ((*_bfd_error_handler) - ("%s: warning: allocated section `%s' not in segment", + (_("%s: warning: allocated section `%s' not in segment"), bfd_get_filename (abfd), (hdr->bfd_section == NULL ? "*unknown*" @@ -2399,7 +3613,7 @@ assign_file_positions_except_relocs (abfd) hdr->sh_offset = -1; else off = _bfd_elf_assign_file_position_for_section (hdr, off, true); - } + } } /* Place the section headers. */ @@ -2417,7 +3631,7 @@ prep_headers (abfd) bfd *abfd; { Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ - Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */ + Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */ Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */ int count; struct bfd_strtab_hash *shstrtab; @@ -2442,6 +3656,9 @@ prep_headers (abfd) bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB; i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current; + i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_NONE; + i_ehdrp->e_ident[EI_ABIVERSION] = 0; + for (count = EI_PAD; count < EI_NIDENT; count++) i_ehdrp->e_ident[count] = 0; @@ -2449,6 +3666,8 @@ prep_headers (abfd) i_ehdrp->e_type = ET_DYN; else if ((abfd->flags & EXEC_P) != 0) i_ehdrp->e_type = ET_EXEC; + else if (bfd_get_format (abfd) == bfd_core) + i_ehdrp->e_type = ET_CORE; else i_ehdrp->e_type = ET_REL; @@ -2457,71 +3676,43 @@ prep_headers (abfd) case bfd_arch_unknown: i_ehdrp->e_machine = EM_NONE; break; - case bfd_arch_sparc: - if (bed->s->arch_size == 64) - i_ehdrp->e_machine = EM_SPARC64; - else - i_ehdrp->e_machine = EM_SPARC; - break; - case bfd_arch_i386: - i_ehdrp->e_machine = EM_386; - break; - case bfd_arch_m68k: - i_ehdrp->e_machine = EM_68K; - break; - case bfd_arch_m88k: - i_ehdrp->e_machine = EM_88K; - break; - case bfd_arch_i860: - i_ehdrp->e_machine = EM_860; - break; - case bfd_arch_mips: /* MIPS Rxxxx */ - i_ehdrp->e_machine = EM_MIPS; /* only MIPS R3000 */ - break; - case bfd_arch_hppa: - i_ehdrp->e_machine = EM_PARISC; - break; - case bfd_arch_powerpc: - i_ehdrp->e_machine = EM_PPC; - break; - case bfd_arch_alpha: - i_ehdrp->e_machine = EM_ALPHA; - break; -/* start-sanitize-d10v */ - case bfd_arch_d10v: - i_ehdrp->e_machine = EM_CYGNUS_D10V; - break; -/* end-sanitize-d10v */ -/* start-sanitize-arc */ - case bfd_arch_arc: - i_ehdrp->e_machine = EM_CYGNUS_ARC; - break; -/* end-sanitize-arc */ - /* also note that EM_M32, AT&T WE32100 is unknown to bfd */ + + /* There used to be a long list of cases here, each one setting + e_machine to the same EM_* macro #defined as ELF_MACHINE_CODE + in the corresponding bfd definition. To avoid duplication, + the switch was removed. Machines that need special handling + can generally do it in elf_backend_final_write_processing(), + unless they need the information earlier than the final write. + Such need can generally be supplied by replacing the tests for + e_machine with the conditions used to determine it. */ default: - i_ehdrp->e_machine = EM_NONE; - } + if (get_elf_backend_data (abfd) != NULL) + i_ehdrp->e_machine = get_elf_backend_data (abfd)->elf_machine_code; + else + i_ehdrp->e_machine = EM_NONE; + } + i_ehdrp->e_version = bed->s->ev_current; i_ehdrp->e_ehsize = bed->s->sizeof_ehdr; - /* no program header, for now. */ + /* No program header, for now. */ i_ehdrp->e_phoff = 0; i_ehdrp->e_phentsize = 0; i_ehdrp->e_phnum = 0; - /* each bfd section is section header entry */ + /* Each bfd section is section header entry. */ i_ehdrp->e_entry = bfd_get_start_address (abfd); i_ehdrp->e_shentsize = bed->s->sizeof_shdr; - /* if we're building an executable, we'll need a program header table */ + /* If we're building an executable, we'll need a program header table. */ if (abfd->flags & EXEC_P) { - /* it all happens later */ + /* It all happens later. */ #if 0 i_ehdrp->e_phentsize = sizeof (Elf_External_Phdr); /* elf_build_phdrs() returns a (NULL-terminated) array of - Elf_Internal_Phdrs */ + Elf_Internal_Phdrs. */ i_phdrp = elf_build_phdrs (abfd, i_ehdrp, i_shdrp, &i_ehdrp->e_phnum); i_ehdrp->e_phoff = outbase; outbase += i_ehdrp->e_phentsize * i_ehdrp->e_phnum; @@ -2587,8 +3778,8 @@ _bfd_elf_write_object_contents (abfd) unsigned int count; if (! abfd->output_has_begun - && ! _bfd_elf_compute_section_file_positions (abfd, - (struct bfd_link_info *) NULL)) + && ! _bfd_elf_compute_section_file_positions + (abfd, (struct bfd_link_info *) NULL)) return false; i_shdrp = elf_elfsections (abfd); @@ -2598,19 +3789,20 @@ _bfd_elf_write_object_contents (abfd) bfd_map_over_sections (abfd, bed->s->write_relocs, &failed); if (failed) return false; + _bfd_elf_assign_file_positions_for_relocs (abfd); - /* After writing the headers, we need to write the sections too... */ + /* After writing the headers, we need to write the sections too... */ for (count = 1; count < i_ehdrp->e_shnum; count++) { if (bed->elf_backend_section_processing) (*bed->elf_backend_section_processing) (abfd, i_shdrp[count]); if (i_shdrp[count]->contents) { + bfd_size_type amt = i_shdrp[count]->sh_size; + if (bfd_seek (abfd, i_shdrp[count]->sh_offset, SEEK_SET) != 0 - || (bfd_write (i_shdrp[count]->contents, i_shdrp[count]->sh_size, - 1, abfd) - != i_shdrp[count]->sh_size)) + || bfd_bwrite (i_shdrp[count]->contents, amt, abfd) != amt) return false; } } @@ -2627,7 +3819,16 @@ _bfd_elf_write_object_contents (abfd) return bed->s->write_shdrs_and_ehdr (abfd); } -/* given a section, search the header to find them... */ +boolean +_bfd_elf_write_corefile_contents (abfd) + bfd *abfd; +{ + /* Hopefully this can be done just like an object file. */ + return _bfd_elf_write_object_contents (abfd); +} + +/* Given a section, search the header to find them. */ + int _bfd_elf_section_from_bfd_section (abfd, asect) bfd *abfd; @@ -2667,6 +3868,8 @@ _bfd_elf_section_from_bfd_section (abfd, asect) if (bfd_is_und_section (asect)) return SHN_UNDEF; + bfd_set_error (bfd_error_nonrepresentable_section); + return -1; } @@ -2697,7 +3900,8 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) indx = asym_ptr->section->output_section->index; else indx = asym_ptr->section->index; - if (elf_section_syms (abfd)[indx]) + if (indx < elf_num_section_syms (abfd) + && elf_section_syms (abfd)[indx] != NULL) asym_ptr->udata.i = elf_section_syms (abfd)[indx]->udata.i; } @@ -2708,8 +3912,8 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) /* This case can occur when using --strip-symbol on a symbol which is used in a relocation entry. */ (*_bfd_error_handler) - ("%s: symbol `%s' required but not present", - bfd_get_filename (abfd), bfd_asymbol_name (asym_ptr)); + (_("%s: symbol `%s' required but not present"), + bfd_archive_filename (abfd), bfd_asymbol_name (asym_ptr)); bfd_set_error (bfd_error_no_symbols); return -1; } @@ -2717,7 +3921,7 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) #if DEBUG & 4 { fprintf (stderr, - "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n", + _("elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n"), (long) asym_ptr, asym_ptr->name, idx, flags, elf_symbol_flags (flags)); fflush (stderr); @@ -2734,11 +3938,18 @@ copy_private_bfd_data (ibfd, obfd) bfd *ibfd; bfd *obfd; { - Elf_Internal_Ehdr *iehdr; - struct elf_segment_map *mfirst; - struct elf_segment_map **pm; - Elf_Internal_Phdr *p; - unsigned int i, c; + Elf_Internal_Ehdr * iehdr; + struct elf_segment_map * map; + struct elf_segment_map * map_first; + struct elf_segment_map ** pointer_to_map; + Elf_Internal_Phdr * segment; + asection * section; + unsigned int i; + unsigned int num_segments; + boolean phdr_included = false; + bfd_vma maxpagesize; + struct elf_segment_map * phdr_adjust_seg = NULL; + unsigned int phdr_adjust_num = 0; if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour || bfd_get_flavour (obfd) != bfd_target_elf_flavour) @@ -2749,86 +3960,526 @@ copy_private_bfd_data (ibfd, obfd) iehdr = elf_elfheader (ibfd); - mfirst = NULL; - pm = &mfirst; + map_first = NULL; + pointer_to_map = &map_first; + + num_segments = elf_elfheader (ibfd)->e_phnum; + maxpagesize = get_elf_backend_data (obfd)->maxpagesize; + + /* Returns the end address of the segment + 1. */ +#define SEGMENT_END(segment, start) \ + (start + (segment->p_memsz > segment->p_filesz \ + ? segment->p_memsz : segment->p_filesz)) + + /* Returns true if the given section is contained within + the given segment. VMA addresses are compared. */ +#define IS_CONTAINED_BY_VMA(section, segment) \ + (section->vma >= segment->p_vaddr \ + && (section->vma + section->_raw_size) \ + <= (SEGMENT_END (segment, segment->p_vaddr))) + + /* Returns true if the given section is contained within + the given segment. LMA addresses are compared. */ +#define IS_CONTAINED_BY_LMA(section, segment, base) \ + (section->lma >= base \ + && (section->lma + section->_raw_size) \ + <= SEGMENT_END (segment, base)) + + /* Special case: corefile "NOTE" section containing regs, prpsinfo etc. */ +#define IS_COREFILE_NOTE(p, s) \ + (p->p_type == PT_NOTE \ + && bfd_get_format (ibfd) == bfd_core \ + && s->vma == 0 && s->lma == 0 \ + && (bfd_vma) s->filepos >= p->p_offset \ + && (bfd_vma) s->filepos + s->_raw_size \ + <= p->p_offset + p->p_filesz) + + /* The complicated case when p_vaddr is 0 is to handle the Solaris + linker, which generates a PT_INTERP section with p_vaddr and + p_memsz set to 0. */ +#define IS_SOLARIS_PT_INTERP(p, s) \ + ( p->p_vaddr == 0 \ + && p->p_filesz > 0 \ + && (s->flags & SEC_HAS_CONTENTS) != 0 \ + && s->_raw_size > 0 \ + && (bfd_vma) s->filepos >= p->p_offset \ + && ((bfd_vma) s->filepos + s->_raw_size \ + <= p->p_offset + p->p_filesz)) + + /* Decide if the given section should be included in the given segment. + A section will be included if: + 1. It is within the address space of the segment, + 2. It is an allocated segment, + 3. There is an output section associated with it, + 4. The section has not already been allocated to a previous segment. */ +#define INCLUDE_SECTION_IN_SEGMENT(section, segment) \ + ((((IS_CONTAINED_BY_VMA (section, segment) \ + || IS_SOLARIS_PT_INTERP (segment, section)) \ + && (section->flags & SEC_ALLOC) != 0) \ + || IS_COREFILE_NOTE (segment, section)) \ + && section->output_section != NULL \ + && section->segment_mark == false) + + /* Returns true iff seg1 starts after the end of seg2. */ +#define SEGMENT_AFTER_SEGMENT(seg1, seg2) \ + (seg1->p_vaddr >= SEGMENT_END (seg2, seg2->p_vaddr)) + + /* Returns true iff seg1 and seg2 overlap. */ +#define SEGMENT_OVERLAPS(seg1, seg2) \ + (!(SEGMENT_AFTER_SEGMENT (seg1, seg2) || SEGMENT_AFTER_SEGMENT (seg2, seg1))) + + /* Initialise the segment mark field. */ + for (section = ibfd->sections; section != NULL; section = section->next) + section->segment_mark = false; + + /* Scan through the segments specified in the program header + of the input BFD. For this first scan we look for overlaps + in the loadable segments. These can be created by wierd + parameters to objcopy. */ + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i++, segment++) + { + unsigned int j; + Elf_Internal_Phdr *segment2; + + if (segment->p_type != PT_LOAD) + continue; + + /* Determine if this segment overlaps any previous segments. */ + for (j = 0, segment2 = elf_tdata (ibfd)->phdr; j < i; j++, segment2 ++) + { + bfd_signed_vma extra_length; + + if (segment2->p_type != PT_LOAD + || ! SEGMENT_OVERLAPS (segment, segment2)) + continue; + + /* Merge the two segments together. */ + if (segment2->p_vaddr < segment->p_vaddr) + { + /* Extend SEGMENT2 to include SEGMENT and then delete + SEGMENT. */ + extra_length = + SEGMENT_END (segment, segment->p_vaddr) + - SEGMENT_END (segment2, segment2->p_vaddr); + + if (extra_length > 0) + { + segment2->p_memsz += extra_length; + segment2->p_filesz += extra_length; + } + + segment->p_type = PT_NULL; + + /* Since we have deleted P we must restart the outer loop. */ + i = 0; + segment = elf_tdata (ibfd)->phdr; + break; + } + else + { + /* Extend SEGMENT to include SEGMENT2 and then delete + SEGMENT2. */ + extra_length = + SEGMENT_END (segment2, segment2->p_vaddr) + - SEGMENT_END (segment, segment->p_vaddr); + + if (extra_length > 0) + { + segment->p_memsz += extra_length; + segment->p_filesz += extra_length; + } + + segment2->p_type = PT_NULL; + } + } + } - c = elf_elfheader (ibfd)->e_phnum; - for (i = 0, p = elf_tdata (ibfd)->phdr; i < c; i++, p++) + /* The second scan attempts to assign sections to segments. */ + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i ++, segment ++) { - unsigned int csecs; - asection *s; - struct elf_segment_map *m; - unsigned int isec; - - csecs = 0; - - /* The complicated case when p_vaddr is 0 is to handle the - Solaris linker, which generates a PT_INTERP section with - p_vaddr and p_memsz set to 0. */ - for (s = ibfd->sections; s != NULL; s = s->next) - if (((s->vma >= p->p_vaddr - && (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz - || s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz)) - || (p->p_vaddr == 0 - && p->p_filesz > 0 - && (s->flags & SEC_HAS_CONTENTS) != 0 - && (bfd_vma) s->filepos >= p->p_offset - && ((bfd_vma) s->filepos + s->_raw_size - <= p->p_offset + p->p_filesz))) - && (s->flags & SEC_ALLOC) != 0 - && s->output_section != NULL) - ++csecs; - - m = ((struct elf_segment_map *) - bfd_alloc (obfd, - (sizeof (struct elf_segment_map) - + (csecs - 1) * sizeof (asection *)))); - if (m == NULL) + unsigned int section_count; + asection ** sections; + asection * output_section; + unsigned int isec; + bfd_vma matching_lma; + bfd_vma suggested_lma; + unsigned int j; + bfd_size_type amt; + + if (segment->p_type == PT_NULL) + continue; + + /* Compute how many sections might be placed into this segment. */ + section_count = 0; + for (section = ibfd->sections; section != NULL; section = section->next) + if (INCLUDE_SECTION_IN_SEGMENT (section, segment)) + ++section_count; + + /* Allocate a segment map big enough to contain all of the + sections we have selected. */ + amt = sizeof (struct elf_segment_map); + amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); + map = (struct elf_segment_map *) bfd_alloc (obfd, amt); + if (map == NULL) return false; - m->next = NULL; - m->p_type = p->p_type; - m->p_flags = p->p_flags; - m->p_flags_valid = 1; - m->p_paddr = p->p_paddr; - m->p_paddr_valid = 1; + /* Initialise the fields of the segment map. Default to + using the physical address of the segment in the input BFD. */ + map->next = NULL; + map->p_type = segment->p_type; + map->p_flags = segment->p_flags; + map->p_flags_valid = 1; + map->p_paddr = segment->p_paddr; + map->p_paddr_valid = 1; + + /* Determine if this segment contains the ELF file header + and if it contains the program headers themselves. */ + map->includes_filehdr = (segment->p_offset == 0 + && segment->p_filesz >= iehdr->e_ehsize); + + map->includes_phdrs = 0; + + if (! phdr_included || segment->p_type != PT_LOAD) + { + map->includes_phdrs = + (segment->p_offset <= (bfd_vma) iehdr->e_phoff + && (segment->p_offset + segment->p_filesz + >= ((bfd_vma) iehdr->e_phoff + + iehdr->e_phnum * iehdr->e_phentsize))); + + if (segment->p_type == PT_LOAD && map->includes_phdrs) + phdr_included = true; + } + + if (section_count == 0) + { + /* Special segments, such as the PT_PHDR segment, may contain + no sections, but ordinary, loadable segments should contain + something. */ + if (segment->p_type == PT_LOAD) + _bfd_error_handler + (_("%s: warning: Empty loadable segment detected\n"), + bfd_archive_filename (ibfd)); + + map->count = 0; + *pointer_to_map = map; + pointer_to_map = &map->next; - m->includes_filehdr = (p->p_offset == 0 - && p->p_filesz >= iehdr->e_ehsize); + continue; + } - m->includes_phdrs = (p->p_offset <= (bfd_vma) iehdr->e_phoff - && (p->p_offset + p->p_filesz - >= ((bfd_vma) iehdr->e_phoff - + iehdr->e_phnum * iehdr->e_phentsize))); + /* Now scan the sections in the input BFD again and attempt + to add their corresponding output sections to the segment map. + The problem here is how to handle an output section which has + been moved (ie had its LMA changed). There are four possibilities: + + 1. None of the sections have been moved. + In this case we can continue to use the segment LMA from the + input BFD. + + 2. All of the sections have been moved by the same amount. + In this case we can change the segment's LMA to match the LMA + of the first section. + + 3. Some of the sections have been moved, others have not. + In this case those sections which have not been moved can be + placed in the current segment which will have to have its size, + and possibly its LMA changed, and a new segment or segments will + have to be created to contain the other sections. + + 4. The sections have been moved, but not be the same amount. + In this case we can change the segment's LMA to match the LMA + of the first section and we will have to create a new segment + or segments to contain the other sections. + + In order to save time, we allocate an array to hold the section + pointers that we are interested in. As these sections get assigned + to a segment, they are removed from this array. */ + + amt = (bfd_size_type) section_count * sizeof (asection *); + sections = (asection **) bfd_malloc (amt); + if (sections == NULL) + return false; + /* Step One: Scan for segment vs section LMA conflicts. + Also add the sections to the section array allocated above. + Also add the sections to the current segment. In the common + case, where the sections have not been moved, this means that + we have completely filled the segment, and there is nothing + more to do. */ isec = 0; - for (s = ibfd->sections; s != NULL; s = s->next) - { - if (((s->vma >= p->p_vaddr - && (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz - || s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz)) - || (p->p_vaddr == 0 - && p->p_filesz > 0 - && (s->flags & SEC_HAS_CONTENTS) != 0 - && (bfd_vma) s->filepos >= p->p_offset - && ((bfd_vma) s->filepos + s->_raw_size - <= p->p_offset + p->p_filesz))) - && (s->flags & SEC_ALLOC) != 0 - && s->output_section != NULL) + matching_lma = 0; + suggested_lma = 0; + + for (j = 0, section = ibfd->sections; + section != NULL; + section = section->next) + { + if (INCLUDE_SECTION_IN_SEGMENT (section, segment)) { - m->sections[isec] = s->output_section; - ++isec; + output_section = section->output_section; + + sections[j ++] = section; + + /* The Solaris native linker always sets p_paddr to 0. + We try to catch that case here, and set it to the + correct value. */ + if (segment->p_paddr == 0 + && segment->p_vaddr != 0 + && isec == 0 + && output_section->lma != 0 + && (output_section->vma == (segment->p_vaddr + + (map->includes_filehdr + ? iehdr->e_ehsize + : 0) + + (map->includes_phdrs + ? iehdr->e_phnum * iehdr->e_phentsize + : 0)))) + map->p_paddr = segment->p_vaddr; + + /* Match up the physical address of the segment with the + LMA address of the output section. */ + if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr) + || IS_COREFILE_NOTE (segment, section)) + { + if (matching_lma == 0) + matching_lma = output_section->lma; + + /* We assume that if the section fits within the segment + then it does not overlap any other section within that + segment. */ + map->sections[isec ++] = output_section; + } + else if (suggested_lma == 0) + suggested_lma = output_section->lma; } } - BFD_ASSERT (isec == csecs); - m->count = csecs; - *pm = m; - pm = &m->next; + BFD_ASSERT (j == section_count); + + /* Step Two: Adjust the physical address of the current segment, + if necessary. */ + if (isec == section_count) + { + /* All of the sections fitted within the segment as currently + specified. This is the default case. Add the segment to + the list of built segments and carry on to process the next + program header in the input BFD. */ + map->count = section_count; + *pointer_to_map = map; + pointer_to_map = &map->next; + + free (sections); + continue; + } + else + { + if (matching_lma != 0) + { + /* At least one section fits inside the current segment. + Keep it, but modify its physical address to match the + LMA of the first section that fitted. */ + map->p_paddr = matching_lma; + } + else + { + /* None of the sections fitted inside the current segment. + Change the current segment's physical address to match + the LMA of the first section. */ + map->p_paddr = suggested_lma; + } + + /* Offset the segment physical address from the lma + to allow for space taken up by elf headers. */ + if (map->includes_filehdr) + map->p_paddr -= iehdr->e_ehsize; + + if (map->includes_phdrs) + { + map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize; + + /* iehdr->e_phnum is just an estimate of the number + of program headers that we will need. Make a note + here of the number we used and the segment we chose + to hold these headers, so that we can adjust the + offset when we know the correct value. */ + phdr_adjust_num = iehdr->e_phnum; + phdr_adjust_seg = map; + } + } + + /* Step Three: Loop over the sections again, this time assigning + those that fit to the current segment and remvoing them from the + sections array; but making sure not to leave large gaps. Once all + possible sections have been assigned to the current segment it is + added to the list of built segments and if sections still remain + to be assigned, a new segment is constructed before repeating + the loop. */ + isec = 0; + do + { + map->count = 0; + suggested_lma = 0; + + /* Fill the current segment with sections that fit. */ + for (j = 0; j < section_count; j++) + { + section = sections[j]; + + if (section == NULL) + continue; + + output_section = section->output_section; + + BFD_ASSERT (output_section != NULL); + + if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr) + || IS_COREFILE_NOTE (segment, section)) + { + if (map->count == 0) + { + /* If the first section in a segment does not start at + the beginning of the segment, then something is + wrong. */ + if (output_section->lma != + (map->p_paddr + + (map->includes_filehdr ? iehdr->e_ehsize : 0) + + (map->includes_phdrs + ? iehdr->e_phnum * iehdr->e_phentsize + : 0))) + abort (); + } + else + { + asection * prev_sec; + + prev_sec = map->sections[map->count - 1]; + + /* If the gap between the end of the previous section + and the start of this section is more than + maxpagesize then we need to start a new segment. */ + if ((BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size, maxpagesize) + < BFD_ALIGN (output_section->lma, maxpagesize)) + || ((prev_sec->lma + prev_sec->_raw_size) > output_section->lma)) + { + if (suggested_lma == 0) + suggested_lma = output_section->lma; + + continue; + } + } + + map->sections[map->count++] = output_section; + ++isec; + sections[j] = NULL; + section->segment_mark = true; + } + else if (suggested_lma == 0) + suggested_lma = output_section->lma; + } + + BFD_ASSERT (map->count > 0); + + /* Add the current segment to the list of built segments. */ + *pointer_to_map = map; + pointer_to_map = &map->next; + + if (isec < section_count) + { + /* We still have not allocated all of the sections to + segments. Create a new segment here, initialise it + and carry on looping. */ + amt = sizeof (struct elf_segment_map); + amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); + map = (struct elf_segment_map *) bfd_alloc (obfd, amt); + if (map == NULL) + return false; + + /* Initialise the fields of the segment map. Set the physical + physical address to the LMA of the first section that has + not yet been assigned. */ + map->next = NULL; + map->p_type = segment->p_type; + map->p_flags = segment->p_flags; + map->p_flags_valid = 1; + map->p_paddr = suggested_lma; + map->p_paddr_valid = 1; + map->includes_filehdr = 0; + map->includes_phdrs = 0; + } + } + while (isec < section_count); + + free (sections); + } + + /* The Solaris linker creates program headers in which all the + p_paddr fields are zero. When we try to objcopy or strip such a + file, we get confused. Check for this case, and if we find it + reset the p_paddr_valid fields. */ + for (map = map_first; map != NULL; map = map->next) + if (map->p_paddr != 0) + break; + if (map == NULL) + { + for (map = map_first; map != NULL; map = map->next) + map->p_paddr_valid = 0; + } + + elf_tdata (obfd)->segment_map = map_first; + + /* If we had to estimate the number of program headers that were + going to be needed, then check our estimate know and adjust + the offset if necessary. */ + if (phdr_adjust_seg != NULL) + { + unsigned int count; + + for (count = 0, map = map_first; map != NULL; map = map->next) + count++; + + if (count > phdr_adjust_num) + phdr_adjust_seg->p_paddr + -= (count - phdr_adjust_num) * iehdr->e_phentsize; } - elf_tdata (obfd)->segment_map = mfirst; +#if 0 + /* Final Step: Sort the segments into ascending order of physical + address. */ + if (map_first != NULL) + { + struct elf_segment_map *prev; + + prev = map_first; + for (map = map_first->next; map != NULL; prev = map, map = map->next) + { + /* Yes I know - its a bubble sort.... */ + if (map->next != NULL && (map->next->p_paddr < map->p_paddr)) + { + /* Swap map and map->next. */ + prev->next = map->next; + map->next = map->next->next; + prev->next->next = map; + + /* Restart loop. */ + map = map_first; + } + } + } +#endif +#undef SEGMENT_END +#undef IS_CONTAINED_BY_VMA +#undef IS_CONTAINED_BY_LMA +#undef IS_COREFILE_NOTE +#undef IS_SOLARIS_PT_INTERP +#undef INCLUDE_SECTION_IN_SEGMENT +#undef SEGMENT_AFTER_SEGMENT +#undef SEGMENT_OVERLAPS return true; } @@ -2858,10 +4509,12 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec) { asection *s; - /* Only set up the segments when all the sections have been set - up. */ - for (s = ibfd->sections; s != NULL; s = s->next) - if (s->output_section == NULL) + /* Only set up the segments if there are no more SEC_ALLOC + sections. FIXME: This won't do the right thing if objcopy is + used to remove the last SEC_ALLOC section, since objcopy + won't call this routine in that case. */ + for (s = isec->next; s != NULL; s = s->next) + if ((s->flags & SEC_ALLOC) != 0) break; if (s == NULL) { @@ -2876,9 +4529,14 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec) ohdr->sh_entsize = ihdr->sh_entsize; if (ihdr->sh_type == SHT_SYMTAB - || ihdr->sh_type == SHT_DYNSYM) + || ihdr->sh_type == SHT_DYNSYM + || ihdr->sh_type == SHT_GNU_verneed + || ihdr->sh_type == SHT_GNU_verdef) ohdr->sh_info = ihdr->sh_info; + elf_section_data (osec)->use_rela_p + = elf_section_data (isec)->use_rela_p; + return true; } @@ -2902,6 +4560,10 @@ _bfd_elf_copy_private_symbol_data (ibfd, isymarg, obfd, osymarg) { elf_symbol_type *isym, *osym; + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + isym = elf_symbol_from (ibfd, isymarg); osym = elf_symbol_from (obfd, osymarg); @@ -2929,16 +4591,17 @@ _bfd_elf_copy_private_symbol_data (ibfd, isymarg, obfd, osymarg) /* Swap out the symbols. */ static boolean -swap_out_syms (abfd, sttp) +swap_out_syms (abfd, sttp, relocatable_p) bfd *abfd; struct bfd_strtab_hash **sttp; + int relocatable_p; { struct elf_backend_data *bed = get_elf_backend_data (abfd); if (!elf_map_symbols (abfd)) return false; - /* Dump out the symtabs. */ + /* Dump out the symtabs. */ { int symcount = bfd_get_symcount (abfd); asymbol **syms = bfd_get_outsymbols (abfd); @@ -2947,6 +4610,7 @@ swap_out_syms (abfd, sttp) Elf_Internal_Shdr *symstrtab_hdr; char *outbound_syms; int idx; + bfd_size_type amt; stt = _bfd_elf_stringtab_init (); if (stt == NULL) @@ -2962,8 +4626,8 @@ swap_out_syms (abfd, sttp) symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; symstrtab_hdr->sh_type = SHT_STRTAB; - outbound_syms = bfd_alloc (abfd, - (1 + symcount) * bed->s->sizeof_sym); + amt = (bfd_size_type) (1 + symcount) * bed->s->sizeof_sym; + outbound_syms = bfd_alloc (abfd, amt); if (outbound_syms == NULL) return false; symtab_hdr->contents = (PTR) outbound_syms; @@ -2989,9 +4653,11 @@ swap_out_syms (abfd, sttp) flagword flags = syms[idx]->flags; int type; - if (flags & BSF_SECTION_SYM) - /* Section symbols have no names. */ - sym.st_name = 0; + if ((flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM) + { + /* Local section symbols have no name. */ + sym.st_name = 0; + } else { sym.st_name = (unsigned long) _bfd_stringtab_add (stt, @@ -3003,7 +4669,8 @@ swap_out_syms (abfd, sttp) type_ptr = elf_symbol_from (abfd, syms[idx]); - if (bfd_is_com_section (syms[idx]->section)) + if ((flags & BSF_SECTION_SYM) == 0 + && bfd_is_com_section (syms[idx]->section)) { /* ELF common symbols put the alignment into the `value' field, and the size into the `size' field. This is backwards from @@ -3014,8 +4681,8 @@ swap_out_syms (abfd, sttp) sym.st_value = value >= 16 ? 16 : (1 << bfd_log2 (value)); else sym.st_value = type_ptr->internal_elf_sym.st_value; - sym.st_shndx = _bfd_elf_section_from_bfd_section (abfd, - syms[idx]->section); + sym.st_shndx = _bfd_elf_section_from_bfd_section + (abfd, syms[idx]->section); } else { @@ -3027,7 +4694,9 @@ swap_out_syms (abfd, sttp) value += sec->output_offset; sec = sec->output_section; } - value += sec->vma; + /* Don't add in the section vma for relocatable output. */ + if (! relocatable_p) + value += sec->vma; sym.st_value = value; sym.st_size = type_ptr ? type_ptr->internal_elf_sym.st_size : 0; @@ -3089,15 +4758,25 @@ swap_out_syms (abfd, sttp) else type = STT_NOTYPE; - if (bfd_is_com_section (syms[idx]->section)) + /* Processor-specific types */ + if (type_ptr != NULL + && bed->elf_backend_get_symbol_type) + type = (*bed->elf_backend_get_symbol_type) (&type_ptr->internal_elf_sym, type); + + if (flags & BSF_SECTION_SYM) + { + if (flags & BSF_GLOBAL) + sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); + else + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + } + else if (bfd_is_com_section (syms[idx]->section)) sym.st_info = ELF_ST_INFO (STB_GLOBAL, type); else if (bfd_is_und_section (syms[idx]->section)) sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK) ? STB_WEAK : STB_GLOBAL), type); - else if (flags & BSF_SECTION_SYM) - sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); else if (flags & BSF_FILE) sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); else @@ -3114,7 +4793,11 @@ swap_out_syms (abfd, sttp) sym.st_info = ELF_ST_INFO (bind, type); } - sym.st_other = 0; + if (type_ptr != NULL) + sym.st_other = type_ptr->internal_elf_sym.st_other; + else + sym.st_other = 0; + bed->s->swap_symbol_out (abfd, &sym, (PTR) outbound_syms); outbound_syms += bed->s->sizeof_sym; } @@ -3176,7 +4859,7 @@ _bfd_elf_get_dynamic_symtab_upper_bound (abfd) long _bfd_elf_get_reloc_upper_bound (abfd, asect) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; sec_ptr asect; { return (asect->reloc_count + 1) * sizeof (arelent *); @@ -3193,8 +4876,9 @@ _bfd_elf_canonicalize_reloc (abfd, section, relptr, symbols) { arelent *tblptr; unsigned int i; + struct elf_backend_data *bed = get_elf_backend_data (abfd); - if (! get_elf_backend_data (abfd)->s->slurp_reloc_table (abfd, section, symbols)) + if (! bed->s->slurp_reloc_table (abfd, section, symbols, false)) return -1; tblptr = section->relocation; @@ -3211,7 +4895,8 @@ _bfd_elf_get_symtab (abfd, alocation) bfd *abfd; asymbol **alocation; { - long symcount = get_elf_backend_data (abfd)->s->slurp_symbol_table (abfd, alocation, false); + struct elf_backend_data *bed = get_elf_backend_data (abfd); + long symcount = bed->s->slurp_symbol_table (abfd, alocation, false); if (symcount >= 0) bfd_get_symcount (abfd) = symcount; @@ -3223,106 +4908,397 @@ _bfd_elf_canonicalize_dynamic_symtab (abfd, alocation) bfd *abfd; asymbol **alocation; { - return get_elf_backend_data (abfd)->s->slurp_symbol_table (abfd, alocation, true); + struct elf_backend_data *bed = get_elf_backend_data (abfd); + return bed->s->slurp_symbol_table (abfd, alocation, true); } -asymbol * -_bfd_elf_make_empty_symbol (abfd) +/* Return the size required for the dynamic reloc entries. Any + section that was actually installed in the BFD, and has type + SHT_REL or SHT_RELA, and uses the dynamic symbol table, is + considered to be a dynamic reloc section. */ + +long +_bfd_elf_get_dynamic_reloc_upper_bound (abfd) bfd *abfd; { - elf_symbol_type *newsym; + long ret; + asection *s; - newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (elf_symbol_type)); - if (!newsym) - return NULL; - else + if (elf_dynsymtab (abfd) == 0) { - newsym->symbol.the_bfd = abfd; - return &newsym->symbol; + bfd_set_error (bfd_error_invalid_operation); + return -1; } -} -void -_bfd_elf_get_symbol_info (ignore_abfd, symbol, ret) - bfd *ignore_abfd; - asymbol *symbol; - symbol_info *ret; -{ - bfd_symbol_info (symbol, ret); -} + ret = sizeof (arelent *); + for (s = abfd->sections; s != NULL; s = s->next) + if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) + && (elf_section_data (s)->this_hdr.sh_type == SHT_REL + || elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) + ret += ((s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize) + * sizeof (arelent *)); -alent * -_bfd_elf_get_lineno (ignore_abfd, symbol) - bfd *ignore_abfd; - asymbol *symbol; -{ - abort (); - return NULL; + return ret; } -boolean -_bfd_elf_set_arch_mach (abfd, arch, machine) +/* Canonicalize the dynamic relocation entries. Note that we return + the dynamic relocations as a single block, although they are + actually associated with particular sections; the interface, which + was designed for SunOS style shared libraries, expects that there + is only one set of dynamic relocs. Any section that was actually + installed in the BFD, and has type SHT_REL or SHT_RELA, and uses + the dynamic symbol table, is considered to be a dynamic reloc + section. */ + +long +_bfd_elf_canonicalize_dynamic_reloc (abfd, storage, syms) bfd *abfd; - enum bfd_architecture arch; - unsigned long machine; + arelent **storage; + asymbol **syms; { - /* If this isn't the right architecture for this backend, and this - isn't the generic backend, fail. */ - if (arch != get_elf_backend_data (abfd)->arch - && arch != bfd_arch_unknown - && get_elf_backend_data (abfd)->arch != bfd_arch_unknown) - return false; + boolean (*slurp_relocs) PARAMS ((bfd *, asection *, asymbol **, boolean)); + asection *s; + long ret; - return bfd_default_set_arch_mach (abfd, arch, machine); -} + if (elf_dynsymtab (abfd) == 0) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } -/* Find the nearest line to a particular section and offset, for error - reporting. */ + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + ret = 0; + for (s = abfd->sections; s != NULL; s = s->next) + { + if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) + && (elf_section_data (s)->this_hdr.sh_type == SHT_REL + || elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) + { + arelent *p; + long count, i; + + if (! (*slurp_relocs) (abfd, s, syms, true)) + return -1; + count = s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize; + p = s->relocation; + for (i = 0; i < count; i++) + *storage++ = p++; + ret += count; + } + } + + *storage = NULL; + + return ret; +} + +/* Read in the version information. */ boolean -_bfd_elf_find_nearest_line (abfd, - section, - symbols, - offset, - filename_ptr, - functionname_ptr, - line_ptr) +_bfd_elf_slurp_version_tables (abfd) bfd *abfd; - asection *section; - asymbol **symbols; - bfd_vma offset; - CONST char **filename_ptr; - CONST char **functionname_ptr; - unsigned int *line_ptr; { - boolean found; - const char *filename; - asymbol *func; - bfd_vma low_func; - asymbol **p; - - if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, - &found, filename_ptr, - functionname_ptr, line_ptr, - &elf_tdata (abfd)->line_info)) - return false; - if (found) - return true; - - if (symbols == NULL) - return false; - - filename = NULL; - func = NULL; - low_func = 0; + bfd_byte *contents = NULL; + bfd_size_type amt; - for (p = symbols; *p != NULL; p++) + if (elf_dynverdef (abfd) != 0) { - elf_symbol_type *q; + Elf_Internal_Shdr *hdr; + Elf_External_Verdef *everdef; + Elf_Internal_Verdef *iverdef; + Elf_Internal_Verdef *iverdefarr; + Elf_Internal_Verdef iverdefmem; + unsigned int i; + unsigned int maxidx; - q = (elf_symbol_type *) *p; + hdr = &elf_tdata (abfd)->dynverdef_hdr; - if (bfd_get_section (&q->symbol) != section) + contents = (bfd_byte *) bfd_malloc (hdr->sh_size); + if (contents == NULL) + goto error_return; + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 + || bfd_bread ((PTR) contents, hdr->sh_size, abfd) != hdr->sh_size) + goto error_return; + + /* We know the number of entries in the section but not the maximum + index. Therefore we have to run through all entries and find + the maximum. */ + everdef = (Elf_External_Verdef *) contents; + maxidx = 0; + for (i = 0; i < hdr->sh_info; ++i) + { + _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem); + + if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) > maxidx) + maxidx = iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION); + + everdef = ((Elf_External_Verdef *) + ((bfd_byte *) everdef + iverdefmem.vd_next)); + } + + amt = (bfd_size_type) maxidx * sizeof (Elf_Internal_Verdef); + elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) bfd_zalloc (abfd, amt); + if (elf_tdata (abfd)->verdef == NULL) + goto error_return; + + elf_tdata (abfd)->cverdefs = maxidx; + + everdef = (Elf_External_Verdef *) contents; + iverdefarr = elf_tdata (abfd)->verdef; + for (i = 0; i < hdr->sh_info; i++) + { + Elf_External_Verdaux *everdaux; + Elf_Internal_Verdaux *iverdaux; + unsigned int j; + + _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem); + + iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1]; + memcpy (iverdef, &iverdefmem, sizeof (Elf_Internal_Verdef)); + + iverdef->vd_bfd = abfd; + + amt = (bfd_size_type) iverdef->vd_cnt * sizeof (Elf_Internal_Verdaux); + iverdef->vd_auxptr = (Elf_Internal_Verdaux *) bfd_alloc (abfd, amt); + if (iverdef->vd_auxptr == NULL) + goto error_return; + + everdaux = ((Elf_External_Verdaux *) + ((bfd_byte *) everdef + iverdef->vd_aux)); + iverdaux = iverdef->vd_auxptr; + for (j = 0; j < iverdef->vd_cnt; j++, iverdaux++) + { + _bfd_elf_swap_verdaux_in (abfd, everdaux, iverdaux); + + iverdaux->vda_nodename = + bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + iverdaux->vda_name); + if (iverdaux->vda_nodename == NULL) + goto error_return; + + if (j + 1 < iverdef->vd_cnt) + iverdaux->vda_nextptr = iverdaux + 1; + else + iverdaux->vda_nextptr = NULL; + + everdaux = ((Elf_External_Verdaux *) + ((bfd_byte *) everdaux + iverdaux->vda_next)); + } + + iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename; + + if (i + 1 < hdr->sh_info) + iverdef->vd_nextdef = iverdef + 1; + else + iverdef->vd_nextdef = NULL; + + everdef = ((Elf_External_Verdef *) + ((bfd_byte *) everdef + iverdef->vd_next)); + } + + free (contents); + contents = NULL; + } + + if (elf_dynverref (abfd) != 0) + { + Elf_Internal_Shdr *hdr; + Elf_External_Verneed *everneed; + Elf_Internal_Verneed *iverneed; + unsigned int i; + + hdr = &elf_tdata (abfd)->dynverref_hdr; + + amt = (bfd_size_type) hdr->sh_info * sizeof (Elf_Internal_Verneed); + elf_tdata (abfd)->verref = + (Elf_Internal_Verneed *) bfd_zalloc (abfd, amt); + if (elf_tdata (abfd)->verref == NULL) + goto error_return; + + elf_tdata (abfd)->cverrefs = hdr->sh_info; + + contents = (bfd_byte *) bfd_malloc (hdr->sh_size); + if (contents == NULL) + goto error_return; + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 + || bfd_bread ((PTR) contents, hdr->sh_size, abfd) != hdr->sh_size) + goto error_return; + + everneed = (Elf_External_Verneed *) contents; + iverneed = elf_tdata (abfd)->verref; + for (i = 0; i < hdr->sh_info; i++, iverneed++) + { + Elf_External_Vernaux *evernaux; + Elf_Internal_Vernaux *ivernaux; + unsigned int j; + + _bfd_elf_swap_verneed_in (abfd, everneed, iverneed); + + iverneed->vn_bfd = abfd; + + iverneed->vn_filename = + bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + iverneed->vn_file); + if (iverneed->vn_filename == NULL) + goto error_return; + + amt = iverneed->vn_cnt; + amt *= sizeof (Elf_Internal_Vernaux); + iverneed->vn_auxptr = (Elf_Internal_Vernaux *) bfd_alloc (abfd, amt); + + evernaux = ((Elf_External_Vernaux *) + ((bfd_byte *) everneed + iverneed->vn_aux)); + ivernaux = iverneed->vn_auxptr; + for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++) + { + _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux); + + ivernaux->vna_nodename = + bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + ivernaux->vna_name); + if (ivernaux->vna_nodename == NULL) + goto error_return; + + if (j + 1 < iverneed->vn_cnt) + ivernaux->vna_nextptr = ivernaux + 1; + else + ivernaux->vna_nextptr = NULL; + + evernaux = ((Elf_External_Vernaux *) + ((bfd_byte *) evernaux + ivernaux->vna_next)); + } + + if (i + 1 < hdr->sh_info) + iverneed->vn_nextref = iverneed + 1; + else + iverneed->vn_nextref = NULL; + + everneed = ((Elf_External_Verneed *) + ((bfd_byte *) everneed + iverneed->vn_next)); + } + + free (contents); + contents = NULL; + } + + return true; + + error_return: + if (contents == NULL) + free (contents); + return false; +} + +asymbol * +_bfd_elf_make_empty_symbol (abfd) + bfd *abfd; +{ + elf_symbol_type *newsym; + bfd_size_type amt = sizeof (elf_symbol_type); + + newsym = (elf_symbol_type *) bfd_zalloc (abfd, amt); + if (!newsym) + return NULL; + else + { + newsym->symbol.the_bfd = abfd; + return &newsym->symbol; + } +} + +void +_bfd_elf_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd ATTRIBUTE_UNUSED; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +/* Return whether a symbol name implies a local symbol. Most targets + use this function for the is_local_label_name entry point, but some + override it. */ + +boolean +_bfd_elf_is_local_label_name (abfd, name) + bfd *abfd ATTRIBUTE_UNUSED; + const char *name; +{ + /* Normal local symbols start with ``.L''. */ + if (name[0] == '.' && name[1] == 'L') + return true; + + /* At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate + DWARF debugging symbols starting with ``..''. */ + if (name[0] == '.' && name[1] == '.') + return true; + + /* gcc will sometimes generate symbols beginning with ``_.L_'' when + emitting DWARF debugging output. I suspect this is actually a + small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call + ASM_GENERATE_INTERNAL_LABEL, and this causes the leading + underscore to be emitted on some ELF targets). For ease of use, + we treat such symbols as local. */ + if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_') + return true; + + return false; +} + +alent * +_bfd_elf_get_lineno (ignore_abfd, symbol) + bfd *ignore_abfd ATTRIBUTE_UNUSED; + asymbol *symbol ATTRIBUTE_UNUSED; +{ + abort (); + return NULL; +} + +boolean +_bfd_elf_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + /* If this isn't the right architecture for this backend, and this + isn't the generic backend, fail. */ + if (arch != get_elf_backend_data (abfd)->arch + && arch != bfd_arch_unknown + && get_elf_backend_data (abfd)->arch != bfd_arch_unknown) + return false; + + return bfd_default_set_arch_mach (abfd, arch, machine); +} + +/* Find the function to a particular section and offset, + for error reporting. */ + +static boolean +elf_find_function (abfd, section, symbols, offset, + filename_ptr, functionname_ptr) + bfd *abfd ATTRIBUTE_UNUSED; + asection *section; + asymbol **symbols; + bfd_vma offset; + const char **filename_ptr; + const char **functionname_ptr; +{ + const char *filename; + asymbol *func; + bfd_vma low_func; + asymbol **p; + + filename = NULL; + func = NULL; + low_func = 0; + + for (p = symbols; *p != NULL; p++) + { + elf_symbol_type *q; + + q = (elf_symbol_type *) *p; + + if (bfd_get_section (&q->symbol) != section) continue; switch (ELF_ST_TYPE (q->internal_elf_sym.st_info)) @@ -3332,6 +5308,7 @@ _bfd_elf_find_nearest_line (abfd, case STT_FILE: filename = bfd_asymbol_name (&q->symbol); break; + case STT_NOTYPE: case STT_FUNC: if (q->symbol.section == section && q->symbol.value >= low_func @@ -3347,8 +5324,70 @@ _bfd_elf_find_nearest_line (abfd, if (func == NULL) return false; - *filename_ptr = filename; - *functionname_ptr = bfd_asymbol_name (func); + if (filename_ptr) + *filename_ptr = filename; + if (functionname_ptr) + *functionname_ptr = bfd_asymbol_name (func); + + return true; +} + +/* Find the nearest line to a particular section and offset, + for error reporting. */ + +boolean +_bfd_elf_find_nearest_line (abfd, section, symbols, offset, + filename_ptr, functionname_ptr, line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *line_ptr; +{ + boolean found; + + if (_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset, + filename_ptr, functionname_ptr, + line_ptr)) + { + if (!*functionname_ptr) + elf_find_function (abfd, section, symbols, offset, + *filename_ptr ? NULL : filename_ptr, + functionname_ptr); + + return true; + } + + if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, + filename_ptr, functionname_ptr, + line_ptr, 0, + &elf_tdata (abfd)->dwarf2_find_line_info)) + { + if (!*functionname_ptr) + elf_find_function (abfd, section, symbols, offset, + *filename_ptr ? NULL : filename_ptr, + functionname_ptr); + + return true; + } + + if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, + &found, filename_ptr, + functionname_ptr, line_ptr, + &elf_tdata (abfd)->line_info)) + return false; + if (found) + return true; + + if (symbols == NULL) + return false; + + if (! elf_find_function (abfd, section, symbols, offset, + filename_ptr, functionname_ptr)) + return false; + *line_ptr = 0; return true; } @@ -3375,17 +5414,17 @@ _bfd_elf_set_section_contents (abfd, section, location, offset, count) bfd_size_type count; { Elf_Internal_Shdr *hdr; + bfd_signed_vma pos; if (! abfd->output_has_begun - && ! _bfd_elf_compute_section_file_positions (abfd, - (struct bfd_link_info *) NULL)) + && ! _bfd_elf_compute_section_file_positions + (abfd, (struct bfd_link_info *) NULL)) return false; hdr = &elf_section_data (section)->this_hdr; - - if (bfd_seek (abfd, hdr->sh_offset + offset, SEEK_SET) == -1) - return false; - if (bfd_write (location, 1, count, abfd) != count) + pos = hdr->sh_offset + offset; + if (bfd_seek (abfd, pos, SEEK_SET) != 0 + || bfd_bwrite (location, count, abfd) != count) return false; return true; @@ -3393,9 +5432,9 @@ _bfd_elf_set_section_contents (abfd, section, location, offset, count) void _bfd_elf_no_info_to_howto (abfd, cache_ptr, dst) - bfd *abfd; - arelent *cache_ptr; - Elf_Internal_Rela *dst; + bfd *abfd ATTRIBUTE_UNUSED; + arelent *cache_ptr ATTRIBUTE_UNUSED; + Elf_Internal_Rela *dst ATTRIBUTE_UNUSED; { abort (); } @@ -3418,37 +5457,37 @@ _bfd_elf_validate_reloc (abfd, areloc) bfd *abfd; arelent *areloc; { - /* Check whether we really have an ELF howto. */ + /* Check whether we really have an ELF howto. */ - if ((*areloc->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec) + if ((*areloc->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec) { bfd_reloc_code_real_type code; reloc_howto_type *howto; - + /* Alien reloc: Try to determine its type to replace it with an - equivalent ELF reloc. */ + equivalent ELF reloc. */ if (areloc->howto->pc_relative) { switch (areloc->howto->bitsize) { case 8: - code = BFD_RELOC_8_PCREL; + code = BFD_RELOC_8_PCREL; break; case 12: - code = BFD_RELOC_12_PCREL; + code = BFD_RELOC_12_PCREL; break; case 16: - code = BFD_RELOC_16_PCREL; + code = BFD_RELOC_16_PCREL; break; case 24: - code = BFD_RELOC_24_PCREL; + code = BFD_RELOC_24_PCREL; break; case 32: - code = BFD_RELOC_32_PCREL; + code = BFD_RELOC_32_PCREL; break; case 64: - code = BFD_RELOC_64_PCREL; + code = BFD_RELOC_64_PCREL; break; default: goto fail; @@ -3469,22 +5508,22 @@ _bfd_elf_validate_reloc (abfd, areloc) switch (areloc->howto->bitsize) { case 8: - code = BFD_RELOC_8; + code = BFD_RELOC_8; break; case 14: - code = BFD_RELOC_14; + code = BFD_RELOC_14; break; case 16: - code = BFD_RELOC_16; + code = BFD_RELOC_16; break; case 26: - code = BFD_RELOC_26; + code = BFD_RELOC_26; break; case 32: - code = BFD_RELOC_32; + code = BFD_RELOC_32; break; case 64: - code = BFD_RELOC_64; + code = BFD_RELOC_64; break; default: goto fail; @@ -3503,8 +5542,764 @@ _bfd_elf_validate_reloc (abfd, areloc) fail: (*_bfd_error_handler) - ("%s: unsupported relocation type %s", - bfd_get_filename (abfd), areloc->howto->name); + (_("%s: unsupported relocation type %s"), + bfd_archive_filename (abfd), areloc->howto->name); bfd_set_error (bfd_error_bad_value); return false; } + +boolean +_bfd_elf_close_and_cleanup (abfd) + bfd *abfd; +{ + if (bfd_get_format (abfd) == bfd_object) + { + if (elf_shstrtab (abfd) != NULL) + _bfd_stringtab_free (elf_shstrtab (abfd)); + } + + return _bfd_generic_close_and_cleanup (abfd); +} + +/* For Rel targets, we encode meaningful data for BFD_RELOC_VTABLE_ENTRY + in the relocation's offset. Thus we cannot allow any sort of sanity + range-checking to interfere. There is nothing else to do in processing + this reloc. */ + +bfd_reloc_status_type +_bfd_elf_rel_vtable_reloc_fn (abfd, re, symbol, data, is, obfd, errmsg) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *re ATTRIBUTE_UNUSED; + struct symbol_cache_entry *symbol ATTRIBUTE_UNUSED; + PTR data ATTRIBUTE_UNUSED; + asection *is ATTRIBUTE_UNUSED; + bfd *obfd ATTRIBUTE_UNUSED; + char **errmsg ATTRIBUTE_UNUSED; +{ + return bfd_reloc_ok; +} + +/* Elf core file support. Much of this only works on native + toolchains, since we rely on knowing the + machine-dependent procfs structure in order to pick + out details about the corefile. */ + +#ifdef HAVE_SYS_PROCFS_H +# include +#endif + +/* FIXME: this is kinda wrong, but it's what gdb wants. */ + +static int +elfcore_make_pid (abfd) + bfd *abfd; +{ + return ((elf_tdata (abfd)->core_lwpid << 16) + + (elf_tdata (abfd)->core_pid)); +} + +/* If there isn't a section called NAME, make one, using + data from SECT. Note, this function will generate a + reference to NAME, so you shouldn't deallocate or + overwrite it. */ + +static boolean +elfcore_maybe_make_sect (abfd, name, sect) + bfd *abfd; + char *name; + asection *sect; +{ + asection *sect2; + + if (bfd_get_section_by_name (abfd, name) != NULL) + return true; + + sect2 = bfd_make_section (abfd, name); + if (sect2 == NULL) + return false; + + sect2->_raw_size = sect->_raw_size; + sect2->filepos = sect->filepos; + sect2->flags = sect->flags; + sect2->alignment_power = sect->alignment_power; + return true; +} + +/* Create a pseudosection containing SIZE bytes at FILEPOS. This + actually creates up to two pseudosections: + - For the single-threaded case, a section named NAME, unless + such a section already exists. + - For the multi-threaded case, a section named "NAME/PID", where + PID is elfcore_make_pid (abfd). + Both pseudosections have identical contents. */ +boolean +_bfd_elfcore_make_pseudosection (abfd, name, size, filepos) + bfd *abfd; + char *name; + size_t size; + ufile_ptr filepos; +{ + char buf[100]; + char *threaded_name; + asection *sect; + + /* Build the section name. */ + + sprintf (buf, "%s/%d", name, elfcore_make_pid (abfd)); + threaded_name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1); + if (threaded_name == NULL) + return false; + strcpy (threaded_name, buf); + + sect = bfd_make_section (abfd, threaded_name); + if (sect == NULL) + return false; + sect->_raw_size = size; + sect->filepos = filepos; + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + return elfcore_maybe_make_sect (abfd, name, sect); +} + +/* prstatus_t exists on: + solaris 2.5+ + linux 2.[01] + glibc + unixware 4.2 +*/ + +#if defined (HAVE_PRSTATUS_T) +static boolean elfcore_grok_prstatus PARAMS ((bfd *, Elf_Internal_Note *)); + +static boolean +elfcore_grok_prstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + size_t raw_size; + int offset; + + if (note->descsz == sizeof (prstatus_t)) + { + prstatus_t prstat; + + raw_size = sizeof (prstat.pr_reg); + offset = offsetof (prstatus_t, pr_reg); + memcpy (&prstat, note->descdata, sizeof (prstat)); + + elf_tdata (abfd)->core_signal = prstat.pr_cursig; + elf_tdata (abfd)->core_pid = prstat.pr_pid; + + /* pr_who exists on: + solaris 2.5+ + unixware 4.2 + pr_who doesn't exist on: + linux 2.[01] + */ +#if defined (HAVE_PRSTATUS_T_PR_WHO) + elf_tdata (abfd)->core_lwpid = prstat.pr_who; +#endif + } +#if defined (HAVE_PRSTATUS32_T) + else if (note->descsz == sizeof (prstatus32_t)) + { + /* 64-bit host, 32-bit corefile */ + prstatus32_t prstat; + + raw_size = sizeof (prstat.pr_reg); + offset = offsetof (prstatus32_t, pr_reg); + memcpy (&prstat, note->descdata, sizeof (prstat)); + + elf_tdata (abfd)->core_signal = prstat.pr_cursig; + elf_tdata (abfd)->core_pid = prstat.pr_pid; + + /* pr_who exists on: + solaris 2.5+ + unixware 4.2 + pr_who doesn't exist on: + linux 2.[01] + */ +#if defined (HAVE_PRSTATUS32_T_PR_WHO) + elf_tdata (abfd)->core_lwpid = prstat.pr_who; +#endif + } +#endif /* HAVE_PRSTATUS32_T */ + else + { + /* Fail - we don't know how to handle any other + note size (ie. data object type). */ + return true; + } + + /* Make a ".reg/999" section and a ".reg" section. */ + return _bfd_elfcore_make_pseudosection (abfd, ".reg", + raw_size, note->descpos + offset); +} +#endif /* defined (HAVE_PRSTATUS_T) */ + +/* Create a pseudosection containing the exact contents of NOTE. */ +static boolean +elfcore_make_note_pseudosection (abfd, name, note) + bfd *abfd; + char *name; + Elf_Internal_Note *note; +{ + return _bfd_elfcore_make_pseudosection (abfd, name, + note->descsz, note->descpos); +} + +/* There isn't a consistent prfpregset_t across platforms, + but it doesn't matter, because we don't have to pick this + data structure apart. */ + +static boolean +elfcore_grok_prfpreg (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + return elfcore_make_note_pseudosection (abfd, ".reg2", note); +} + +/* Linux dumps the Intel SSE regs in a note named "LINUX" with a note + type of 5 (NT_PRXFPREG). Just include the whole note's contents + literally. */ + +static boolean +elfcore_grok_prxfpreg (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note); +} + +#if defined (HAVE_PRPSINFO_T) +typedef prpsinfo_t elfcore_psinfo_t; +#if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */ +typedef prpsinfo32_t elfcore_psinfo32_t; +#endif +#endif + +#if defined (HAVE_PSINFO_T) +typedef psinfo_t elfcore_psinfo_t; +#if defined (HAVE_PSINFO32_T) /* Sparc64 cross Sparc32 */ +typedef psinfo32_t elfcore_psinfo32_t; +#endif +#endif + +/* return a malloc'ed copy of a string at START which is at + most MAX bytes long, possibly without a terminating '\0'. + the copy will always have a terminating '\0'. */ + +char * +_bfd_elfcore_strndup (abfd, start, max) + bfd *abfd; + char *start; + size_t max; +{ + char *dups; + char *end = memchr (start, '\0', max); + size_t len; + + if (end == NULL) + len = max; + else + len = end - start; + + dups = bfd_alloc (abfd, (bfd_size_type) len + 1); + if (dups == NULL) + return NULL; + + memcpy (dups, start, len); + dups[len] = '\0'; + + return dups; +} + +#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) +static boolean elfcore_grok_psinfo PARAMS ((bfd *, Elf_Internal_Note *)); + +static boolean +elfcore_grok_psinfo (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + if (note->descsz == sizeof (elfcore_psinfo_t)) + { + elfcore_psinfo_t psinfo; + + memcpy (&psinfo, note->descdata, sizeof (psinfo)); + + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, psinfo.pr_fname, + sizeof (psinfo.pr_fname)); + + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, psinfo.pr_psargs, + sizeof (psinfo.pr_psargs)); + } +#if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T) + else if (note->descsz == sizeof (elfcore_psinfo32_t)) + { + /* 64-bit host, 32-bit corefile */ + elfcore_psinfo32_t psinfo; + + memcpy (&psinfo, note->descdata, sizeof (psinfo)); + + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, psinfo.pr_fname, + sizeof (psinfo.pr_fname)); + + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, psinfo.pr_psargs, + sizeof (psinfo.pr_psargs)); + } +#endif + + else + { + /* Fail - we don't know how to handle any other + note size (ie. data object type). */ + return true; + } + + /* Note that for some reason, a spurious space is tacked + onto the end of the args in some (at least one anyway) + implementations, so strip it off if it exists. */ + + { + char *command = elf_tdata (abfd)->core_command; + int n = strlen (command); + + if (0 < n && command[n - 1] == ' ') + command[n - 1] = '\0'; + } + + return true; +} +#endif /* defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) */ + +#if defined (HAVE_PSTATUS_T) +static boolean +elfcore_grok_pstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + if (note->descsz == sizeof (pstatus_t) +#if defined (HAVE_PXSTATUS_T) + || note->descsz == sizeof (pxstatus_t) +#endif + ) + { + pstatus_t pstat; + + memcpy (&pstat, note->descdata, sizeof (pstat)); + + elf_tdata (abfd)->core_pid = pstat.pr_pid; + } +#if defined (HAVE_PSTATUS32_T) + else if (note->descsz == sizeof (pstatus32_t)) + { + /* 64-bit host, 32-bit corefile */ + pstatus32_t pstat; + + memcpy (&pstat, note->descdata, sizeof (pstat)); + + elf_tdata (abfd)->core_pid = pstat.pr_pid; + } +#endif + /* Could grab some more details from the "representative" + lwpstatus_t in pstat.pr_lwp, but we'll catch it all in an + NT_LWPSTATUS note, presumably. */ + + return true; +} +#endif /* defined (HAVE_PSTATUS_T) */ + +#if defined (HAVE_LWPSTATUS_T) +static boolean +elfcore_grok_lwpstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + lwpstatus_t lwpstat; + char buf[100]; + char *name; + asection *sect; + + if (note->descsz != sizeof (lwpstat) +#if defined (HAVE_LWPXSTATUS_T) + && note->descsz != sizeof (lwpxstatus_t) +#endif + ) + return true; + + memcpy (&lwpstat, note->descdata, sizeof (lwpstat)); + + elf_tdata (abfd)->core_lwpid = lwpstat.pr_lwpid; + elf_tdata (abfd)->core_signal = lwpstat.pr_cursig; + + /* Make a ".reg/999" section. */ + + sprintf (buf, ".reg/%d", elfcore_make_pid (abfd)); + name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1); + if (name == NULL) + return false; + strcpy (name, buf); + + sect = bfd_make_section (abfd, name); + if (sect == NULL) + return false; + +#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT) + sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.gregs); + sect->filepos = note->descpos + + offsetof (lwpstatus_t, pr_context.uc_mcontext.gregs); +#endif + +#if defined (HAVE_LWPSTATUS_T_PR_REG) + sect->_raw_size = sizeof (lwpstat.pr_reg); + sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg); +#endif + + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + if (!elfcore_maybe_make_sect (abfd, ".reg", sect)) + return false; + + /* Make a ".reg2/999" section */ + + sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd)); + name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1); + if (name == NULL) + return false; + strcpy (name, buf); + + sect = bfd_make_section (abfd, name); + if (sect == NULL) + return false; + +#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT) + sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs); + sect->filepos = note->descpos + + offsetof (lwpstatus_t, pr_context.uc_mcontext.fpregs); +#endif + +#if defined (HAVE_LWPSTATUS_T_PR_FPREG) + sect->_raw_size = sizeof (lwpstat.pr_fpreg); + sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg); +#endif + + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + return elfcore_maybe_make_sect (abfd, ".reg2", sect); +} +#endif /* defined (HAVE_LWPSTATUS_T) */ + +#if defined (HAVE_WIN32_PSTATUS_T) +static boolean +elfcore_grok_win32pstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + char buf[30]; + char *name; + asection *sect; + win32_pstatus_t pstatus; + + if (note->descsz < sizeof (pstatus)) + return true; + + memcpy (&pstatus, note->descdata, note->descsz); + + switch (pstatus.data_type) + { + case NOTE_INFO_PROCESS: + /* FIXME: need to add ->core_command. */ + elf_tdata (abfd)->core_signal = pstatus.data.process_info.signal; + elf_tdata (abfd)->core_pid = pstatus.data.process_info.pid; + break; + + case NOTE_INFO_THREAD: + /* Make a ".reg/999" section. */ + sprintf (buf, ".reg/%d", pstatus.data.thread_info.tid); + + name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1); + if (name == NULL) + return false; + + strcpy (name, buf); + + sect = bfd_make_section (abfd, name); + if (sect == NULL) + return false; + + sect->_raw_size = sizeof (pstatus.data.thread_info.thread_context); + sect->filepos = note->descpos + offsetof (struct win32_pstatus, + data.thread_info.thread_context); + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + if (pstatus.data.thread_info.is_active_thread) + if (! elfcore_maybe_make_sect (abfd, ".reg", sect)) + return false; + break; + + case NOTE_INFO_MODULE: + /* Make a ".module/xxxxxxxx" section. */ + sprintf (buf, ".module/%08x", pstatus.data.module_info.base_address); + + name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1); + if (name == NULL) + return false; + + strcpy (name, buf); + + sect = bfd_make_section (abfd, name); + + if (sect == NULL) + return false; + + sect->_raw_size = note->descsz; + sect->filepos = note->descpos; + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + break; + + default: + return true; + } + + return true; +} +#endif /* HAVE_WIN32_PSTATUS_T */ + +static boolean +elfcore_grok_note (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + switch (note->type) + { + default: + return true; + + case NT_PRSTATUS: + if (bed->elf_backend_grok_prstatus) + if ((*bed->elf_backend_grok_prstatus) (abfd, note)) + return true; +#if defined (HAVE_PRSTATUS_T) + return elfcore_grok_prstatus (abfd, note); +#else + return true; +#endif + +#if defined (HAVE_PSTATUS_T) + case NT_PSTATUS: + return elfcore_grok_pstatus (abfd, note); +#endif + +#if defined (HAVE_LWPSTATUS_T) + case NT_LWPSTATUS: + return elfcore_grok_lwpstatus (abfd, note); +#endif + + case NT_FPREGSET: /* FIXME: rename to NT_PRFPREG */ + return elfcore_grok_prfpreg (abfd, note); + +#if defined (HAVE_WIN32_PSTATUS_T) + case NT_WIN32PSTATUS: + return elfcore_grok_win32pstatus (abfd, note); +#endif + + case NT_PRXFPREG: /* Linux SSE extension */ + if (note->namesz == 5 + && ! strcmp (note->namedata, "LINUX")) + return elfcore_grok_prxfpreg (abfd, note); + else + return true; + + case NT_PRPSINFO: + case NT_PSINFO: + if (bed->elf_backend_grok_psinfo) + if ((*bed->elf_backend_grok_psinfo) (abfd, note)) + return true; +#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) + return elfcore_grok_psinfo (abfd, note); +#else + return true; +#endif + } +} + +static boolean +elfcore_read_notes (abfd, offset, size) + bfd *abfd; + file_ptr offset; + bfd_size_type size; +{ + char *buf; + char *p; + + if (size <= 0) + return true; + + if (bfd_seek (abfd, offset, SEEK_SET) != 0) + return false; + + buf = bfd_malloc (size); + if (buf == NULL) + return false; + + if (bfd_bread (buf, size, abfd) != size) + { + error: + free (buf); + return false; + } + + p = buf; + while (p < buf + size) + { + /* FIXME: bad alignment assumption. */ + Elf_External_Note *xnp = (Elf_External_Note *) p; + Elf_Internal_Note in; + + in.type = H_GET_32 (abfd, xnp->type); + + in.namesz = H_GET_32 (abfd, xnp->namesz); + in.namedata = xnp->name; + + in.descsz = H_GET_32 (abfd, xnp->descsz); + in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4); + in.descpos = offset + (in.descdata - buf); + + if (! elfcore_grok_note (abfd, &in)) + goto error; + + p = in.descdata + BFD_ALIGN (in.descsz, 4); + } + + free (buf); + return true; +} + +/* Providing external access to the ELF program header table. */ + +/* Return an upper bound on the number of bytes required to store a + copy of ABFD's program header table entries. Return -1 if an error + occurs; bfd_get_error will return an appropriate code. */ + +long +bfd_get_elf_phdr_upper_bound (abfd) + bfd *abfd; +{ + if (abfd->xvec->flavour != bfd_target_elf_flavour) + { + bfd_set_error (bfd_error_wrong_format); + return -1; + } + + return elf_elfheader (abfd)->e_phnum * sizeof (Elf_Internal_Phdr); +} + +/* Copy ABFD's program header table entries to *PHDRS. The entries + will be stored as an array of Elf_Internal_Phdr structures, as + defined in include/elf/internal.h. To find out how large the + buffer needs to be, call bfd_get_elf_phdr_upper_bound. + + Return the number of program header table entries read, or -1 if an + error occurs; bfd_get_error will return an appropriate code. */ + +int +bfd_get_elf_phdrs (abfd, phdrs) + bfd *abfd; + void *phdrs; +{ + int num_phdrs; + + if (abfd->xvec->flavour != bfd_target_elf_flavour) + { + bfd_set_error (bfd_error_wrong_format); + return -1; + } + + num_phdrs = elf_elfheader (abfd)->e_phnum; + memcpy (phdrs, elf_tdata (abfd)->phdr, + num_phdrs * sizeof (Elf_Internal_Phdr)); + + return num_phdrs; +} + +void +_bfd_elf_sprintf_vma (abfd, buf, value) + bfd *abfd ATTRIBUTE_UNUSED; + char *buf; + bfd_vma value; +{ +#ifdef BFD64 + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + + i_ehdrp = elf_elfheader (abfd); + if (i_ehdrp == NULL) + sprintf_vma (buf, value); + else + { + if (i_ehdrp->e_ident[EI_CLASS] == ELFCLASS64) + { +#if BFD_HOST_64BIT_LONG + sprintf (buf, "%016lx", value); +#else + sprintf (buf, "%08lx%08lx", _bfd_int64_high (value), + _bfd_int64_low (value)); +#endif + } + else + sprintf (buf, "%08lx", (unsigned long) (value & 0xffffffff)); + } +#else + sprintf_vma (buf, value); +#endif +} + +void +_bfd_elf_fprintf_vma (abfd, stream, value) + bfd *abfd ATTRIBUTE_UNUSED; + PTR stream; + bfd_vma value; +{ +#ifdef BFD64 + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + + i_ehdrp = elf_elfheader (abfd); + if (i_ehdrp == NULL) + fprintf_vma ((FILE *) stream, value); + else + { + if (i_ehdrp->e_ident[EI_CLASS] == ELFCLASS64) + { +#if BFD_HOST_64BIT_LONG + fprintf ((FILE *) stream, "%016lx", value); +#else + fprintf ((FILE *) stream, "%08lx%08lx", + _bfd_int64_high (value), _bfd_int64_low (value)); +#endif + } + else + fprintf ((FILE *) stream, "%08lx", + (unsigned long) (value & 0xffffffff)); + } +#else + fprintf_vma ((FILE *) stream, value); +#endif +} + +enum elf_reloc_type_class +_bfd_elf_reloc_type_class (rela) + const Elf_Internal_Rela *rela ATTRIBUTE_UNUSED; +{ + return reloc_class_normal; +}