From a7e831079363e3bb45f3172f6e59ba48e335682b Mon Sep 17 00:00:00 2001 From: Niklas Hallqvist Date: Mon, 10 Jun 1996 10:55:58 +0000 Subject: Bring Cygnus versions into the trunk, keeping our local patches --- gnu/usr.bin/binutils/bfd/elf.c | 1594 ++++++++++++++++++++++++++-------------- 1 file changed, 1059 insertions(+), 535 deletions(-) (limited to 'gnu/usr.bin/binutils/bfd/elf.c') diff --git a/gnu/usr.bin/binutils/bfd/elf.c b/gnu/usr.bin/binutils/bfd/elf.c index e52ad75e1a7..57a46a39a62 100644 --- a/gnu/usr.bin/binutils/bfd/elf.c +++ b/gnu/usr.bin/binutils/bfd/elf.c @@ -1,5 +1,5 @@ /* ELF executable support for BFD. - Copyright 1993 Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -38,13 +38,14 @@ SECTION #define ARCH_SIZE 0 #include "elf-bfd.h" -static file_ptr map_program_segments PARAMS ((bfd *, file_ptr, - Elf_Internal_Shdr *, - Elf_Internal_Shdr **, - bfd_size_type)); +static INLINE struct elf_segment_map *make_mapping + PARAMS ((bfd *, asection **, unsigned int, unsigned int, boolean)); +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 copy_private_bfd_data PARAMS ((bfd *, bfd *)); /* Standard ELF hash function. Do not change this function; you will cause invalid hash tables to be generated. (Well, you would if this @@ -82,10 +83,7 @@ elf_read (abfd, offset, size) char *buf; if ((buf = bfd_alloc (abfd, size)) == NULL) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } + return NULL; if (bfd_seek (abfd, offset, SEEK_SET) == -1) return NULL; if (bfd_read ((PTR) buf, size, 1, abfd) != size) @@ -106,10 +104,7 @@ elf_mkobject (abfd) elf_tdata (abfd) = (struct elf_obj_tdata *) bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); if (elf_tdata (abfd) == 0) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; /* since everything is done at close time, do we need any initialization? */ @@ -229,6 +224,7 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name) 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) @@ -330,6 +326,163 @@ bfd_elf_generic_reloc (abfd, return bfd_reloc_continue; } +/* Print out the program headers. */ + +boolean +_bfd_elf_print_private_bfd_data (abfd, farg) + bfd *abfd; + PTR farg; +{ + FILE *f = (FILE *) farg; + Elf_Internal_Phdr *p; + asection *s; + bfd_byte *dynbuf = NULL; + + p = elf_tdata (abfd)->phdr; + if (p != NULL) + { + unsigned int i, c; + + fprintf (f, "\nProgram Header:\n"); + c = elf_elfheader (abfd)->e_phnum; + for (i = 0; i < c; i++, p++) + { + const char *s; + 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; + } + fprintf (f, "%8s off 0x", s); + fprintf_vma (f, p->p_offset); + fprintf (f, " vaddr 0x"); + fprintf_vma (f, p->p_vaddr); + fprintf (f, " paddr 0x"); + fprintf_vma (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); + fprintf (f, " memsz 0x"); + fprintf_vma (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)); + fprintf (f, "\n"); + } + } + + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s != NULL) + { + int elfsec; + unsigned long link; + bfd_byte *extdyn, *extdynend; + size_t extdynsize; + void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); + + fprintf (f, "\nDynamic Section:\n"); + + 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; + link = 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; + const char *name; + char ab[20]; + boolean stringp; + + (*swap_dyn_in) (abfd, (PTR) extdyn, &dyn); + + if (dyn.d_tag == DT_NULL) + break; + + stringp = false; + switch (dyn.d_tag) + { + default: + sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag); + name = ab; + break; + + case DT_NEEDED: name = "NEEDED"; stringp = true; break; + case DT_PLTRELSZ: name = "PLTRELSZ"; break; + case DT_PLTGOT: name = "PLTGOT"; break; + case DT_HASH: name = "HASH"; break; + case DT_STRTAB: name = "STRTAB"; break; + case DT_SYMTAB: name = "SYMTAB"; break; + case DT_RELA: name = "RELA"; break; + case DT_RELASZ: name = "RELASZ"; break; + case DT_RELAENT: name = "RELAENT"; break; + case DT_STRSZ: name = "STRSZ"; break; + case DT_SYMENT: name = "SYMENT"; break; + case DT_INIT: name = "INIT"; break; + case DT_FINI: name = "FINI"; break; + case DT_SONAME: name = "SONAME"; stringp = true; break; + case DT_RPATH: name = "RPATH"; stringp = true; break; + case DT_SYMBOLIC: name = "SYMBOLIC"; break; + case DT_REL: name = "REL"; break; + case DT_RELSZ: name = "RELSZ"; break; + case DT_RELENT: name = "RELENT"; break; + case DT_PLTREL: name = "PLTREL"; break; + case DT_DEBUG: name = "DEBUG"; break; + case DT_TEXTREL: name = "TEXTREL"; break; + case DT_JMPREL: name = "JMPREL"; break; + } + + fprintf (f, " %-11s ", name); + if (! stringp) + fprintf (f, "0x%lx", (unsigned long) dyn.d_un.d_val); + else + { + const char *string; + + string = bfd_elf_string_from_elf_section (abfd, link, + dyn.d_un.d_val); + if (string == NULL) + goto error_return; + fprintf (f, "%s", string); + } + fprintf (f, "\n"); + } + + free (dynbuf); + dynbuf = NULL; + } + + return true; + + error_return: + if (dynbuf != NULL) + free (dynbuf); + return false; +} + /* Display ELF-specific fields of a symbol. */ void bfd_elf_print_symbol (ignore_abfd, filep, symbol, how) @@ -385,10 +538,7 @@ _bfd_elf_link_hash_newfunc (entry, table, string) ret = ((struct elf_link_hash_entry *) bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry))); if (ret == (struct elf_link_hash_entry *) NULL) - { - bfd_set_error (bfd_error_no_memory); - return (struct bfd_hash_entry *) ret; - } + return (struct bfd_hash_entry *) ret; /* Call the allocation method of the superclass. */ ret = ((struct elf_link_hash_entry *) @@ -404,8 +554,13 @@ _bfd_elf_link_hash_newfunc (entry, table, string) 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->type = STT_NOTYPE; - ret->elf_link_hash_flags = 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 + reader will have the flag set correctly. */ + ret->elf_link_hash_flags = ELF_LINK_NON_ELF; } return (struct bfd_hash_entry *) ret; @@ -428,6 +583,8 @@ _bfd_elf_link_hash_table_init (table, abfd, newfunc) table->dynstr = NULL; table->bucketcount = 0; table->needed = NULL; + table->hgot = NULL; + table->stab_info = NULL; return _bfd_link_hash_table_init (&table->root, abfd, newfunc); } @@ -442,10 +599,7 @@ _bfd_elf_link_hash_table_create (abfd) ret = ((struct elf_link_hash_table *) bfd_alloc (abfd, sizeof (struct elf_link_hash_table))); if (ret == (struct elf_link_hash_table *) NULL) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } + return NULL; if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc)) { @@ -466,11 +620,13 @@ bfd_elf_set_dt_needed_name (abfd, name) bfd *abfd; const char *name; { - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) - elf_dt_needed_name (abfd) = name; + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + elf_dt_name (abfd) = name; } -/* Get the list of DT_NEEDED entries for a link. */ +/* Get the list of DT_NEEDED entries for a link. This is a hook for + the ELF emulation code. */ struct bfd_link_needed_list * bfd_elf_get_needed_list (abfd, info) @@ -481,6 +637,20 @@ bfd_elf_get_needed_list (abfd, info) return NULL; return elf_hash_table (info)->needed; } + +/* 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. */ + +const char * +bfd_elf_get_dt_soname (abfd) + bfd *abfd; +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + return elf_dt_name (abfd); + return NULL; +} /* Allocate an ELF string table--force the first byte to be zero. */ @@ -531,6 +701,7 @@ bfd_section_from_shdr (abfd, shindex) case SHT_DYNAMIC: /* Dynamic linking information. */ case SHT_NOBITS: /* .bss section. */ case SHT_HASH: /* .hash section. */ + case SHT_NOTE: /* .note section. */ return _bfd_elf_make_section_from_shdr (abfd, hdr, name); case SHT_SYMTAB: /* A symbol table */ @@ -630,7 +801,6 @@ bfd_section_from_shdr (abfd, shindex) { asection *target_sect; Elf_Internal_Shdr *hdr2; - int use_rela_p = get_elf_backend_data (abfd)->use_rela_p; /* For some incomprehensible reason Oracle distributes libraries for Solaris in which some of the objects have @@ -675,30 +845,24 @@ bfd_section_from_shdr (abfd, shindex) if (hdr->sh_link != elf_onesymtab (abfd)) return _bfd_elf_make_section_from_shdr (abfd, hdr, name); - /* Don't allow REL relocations on a machine that uses RELA and - vice versa. */ - /* @@ Actually, the generic ABI does suggest that both might be - used in one file. But the four ABI Processor Supplements I - have access to right now all specify that only one is used on - each of those architectures. It's conceivable that, e.g., a - bunch of absolute 32-bit relocs might be more compact in REL - form even on a RELA machine... */ - BFD_ASSERT (use_rela_p - ? (hdr->sh_type == SHT_RELA - && hdr->sh_entsize == bed->s->sizeof_rela) - : (hdr->sh_type == SHT_REL - && hdr->sh_entsize == bed->s->sizeof_rel)); - if (! bfd_section_from_shdr (abfd, hdr->sh_info)) return false; target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info); if (target_sect == NULL) return false; - hdr2 = &elf_section_data (target_sect)->rel_hdr; + if ((target_sect->flags & SEC_RELOC) == 0 + || target_sect->reloc_count == 0) + hdr2 = &elf_section_data (target_sect)->rel_hdr; + else + { + BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL); + hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2)); + 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 += hdr->sh_size / hdr->sh_entsize; target_sect->flags |= SEC_RELOC; target_sect->relocation = NULL; target_sect->rel_filepos = hdr->sh_offset; @@ -707,9 +871,6 @@ bfd_section_from_shdr (abfd, shindex) } break; - case SHT_NOTE: - break; - case SHT_SHLIB: return true; @@ -748,10 +909,7 @@ _bfd_elf_new_section_hook (abfd, sec) sdata = (struct bfd_elf_section_data *) bfd_alloc (abfd, sizeof (*sdata)); if (!sdata) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; sec->used_by_bfd = (PTR) sdata; memset (sdata, 0, sizeof (*sdata)); return true; @@ -796,10 +954,7 @@ bfd_section_from_phdr (abfd, hdr, index) sprintf (namebuf, split ? "segment%da" : "segment%d", index); name = bfd_alloc (abfd, strlen (namebuf) + 1); if (!name) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; strcpy (name, namebuf); newsect = bfd_make_section (abfd, name); if (newsect == NULL) @@ -830,10 +985,7 @@ bfd_section_from_phdr (abfd, hdr, index) sprintf (namebuf, "segment%db", index); name = bfd_alloc (abfd, strlen (namebuf) + 1); if (!name) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; strcpy (name, namebuf); newsect = bfd_make_section (abfd, name); if (newsect == NULL) @@ -976,7 +1128,6 @@ elf_fake_sections (abfd, asect, failedptrarg) name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name)); if (name == NULL) { - bfd_set_error (bfd_error_no_memory); *failedptr = true; return; } @@ -1045,17 +1196,13 @@ assign_section_numbers (abfd) i_shdrp = ((Elf_Internal_Shdr **) bfd_alloc (abfd, section_number * sizeof (Elf_Internal_Shdr *))); if (i_shdrp == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; i_shdrp[0] = ((Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (Elf_Internal_Shdr))); if (i_shdrp[0] == NULL) { bfd_release (abfd, i_shdrp); - bfd_set_error (bfd_error_no_memory); return false; } memset (i_shdrp[0], 0, sizeof (Elf_Internal_Shdr)); @@ -1127,12 +1274,9 @@ assign_section_numbers (abfd) char *alc; len = strlen (sec->name); - alc = (char *) malloc (len - 2); + alc = (char *) bfd_malloc (len - 2); if (alc == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; strncpy (alc, sec->name, len - 3); alc[len - 3] = '\0'; s = bfd_get_section_by_name (abfd, alc); @@ -1221,10 +1365,7 @@ elf_map_symbols (abfd) max_index++; sect_syms = (asymbol **) bfd_zalloc (abfd, max_index * sizeof (asymbol *)); if (sect_syms == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; elf_section_syms (abfd) = sect_syms; for (idx = 0; idx < symcount; idx++) @@ -1301,10 +1442,7 @@ elf_map_symbols (abfd) bfd_alloc (abfd, (num_locals + num_globals) * sizeof (asymbol *))); if (new_syms == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; for (idx = 0; idx < symcount; idx++) { @@ -1462,393 +1600,625 @@ _bfd_elf_compute_section_file_positions (abfd, link_info) return true; } -/* Get the size of the program header. +/* Create a mapping from a set of sections to a program segment. */ - SORTED_HDRS, if non-NULL, is an array of COUNT pointers to headers sorted - by VMA. Non-allocated sections (!SHF_ALLOC) must appear last. All - section VMAs and sizes are known so we can compute the correct value. - (??? This may not be perfectly true. What cases do we miss?) +static INLINE struct elf_segment_map * +make_mapping (abfd, sections, from, to, phdr) + bfd *abfd; + asection **sections; + unsigned int from; + unsigned int to; + boolean phdr; +{ + struct elf_segment_map *m; + unsigned int i; + asection **hdrpp; - If SORTED_HDRS is NULL we assume there are two segments: text and data - (exclusive of .interp and .dynamic). + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, + (sizeof (struct elf_segment_map) + + (to - from - 1) * sizeof (asection *)))); + if (m == NULL) + return NULL; + m->next = NULL; + m->p_type = PT_LOAD; + for (i = from, hdrpp = sections + from; i < to; i++, hdrpp++) + m->sections[i - from] = *hdrpp; + m->count = to - from; - If this is called by the linker before any of the section VMA's are set, it - can't calculate the correct value for a strange memory layout. This only - happens when SIZEOF_HEADERS is used in a linker script. In this case, - SORTED_HDRS is NULL and we assume the normal scenario of one text and one - data segment (exclusive of .interp and .dynamic). + if (from == 0 && phdr) + { + /* Include the headers in the first PT_LOAD segment. */ + m->includes_filehdr = 1; + m->includes_phdrs = 1; + } - ??? User written scripts must either not use SIZEOF_HEADERS, or assume there - will be two segments. */ + return m; +} -static bfd_size_type -get_program_header_size (abfd, sorted_hdrs, count, maxpagesize) +/* Set up a mapping from BFD sections to program segments. */ + +static boolean +map_sections_to_segments (abfd) bfd *abfd; - Elf_Internal_Shdr **sorted_hdrs; - unsigned int count; - bfd_vma maxpagesize; { - size_t segs; + asection **sections = NULL; asection *s; - struct elf_backend_data *bed = get_elf_backend_data (abfd); + unsigned int i; + unsigned int count; + struct elf_segment_map *mfirst; + struct elf_segment_map **pm; + struct elf_segment_map *m; + asection *last_hdr; + unsigned int phdr_index; + bfd_vma maxpagesize; + asection **hdrpp; + boolean phdr_in_section = true; + boolean writable; + asection *dynsec; + + if (elf_tdata (abfd)->segment_map != NULL) + return true; - /* We can't return a different result each time we're called. */ - if (elf_tdata (abfd)->program_header_size != 0) - return elf_tdata (abfd)->program_header_size; + if (bfd_count_sections (abfd) == 0) + return true; - if (sorted_hdrs != NULL) + /* Select the allocated sections, and sort them. */ + + sections = (asection **) bfd_malloc (bfd_count_sections (abfd) + * sizeof (asection *)); + if (sections == NULL) + goto error_return; + + i = 0; + for (s = abfd->sections; s != NULL; s = s->next) { - unsigned int i; - unsigned int last_type; - Elf_Internal_Shdr **hdrpp; - /* What we think the current segment's offset is. */ - bfd_vma p_offset; - /* What we think the current segment's address is. */ - bfd_vma p_vaddr; - /* How big we think the current segment is. */ - bfd_vma p_memsz; - /* What we think the current file offset is. */ - bfd_vma file_offset; - bfd_vma next_offset; - - /* Scan the headers and compute the number of segments required. This - code is intentionally similar to the code in map_program_segments. - - The `sh_offset' field isn't valid at this point, so we keep our own - running total in `file_offset'. - - This works because section VMAs are already known. */ - - segs = 1; - /* Make sure the first section goes in the first segment. */ - file_offset = p_offset = sorted_hdrs[0]->sh_addr % maxpagesize; - p_vaddr = sorted_hdrs[0]->sh_addr; - p_memsz = 0; - last_type = SHT_PROGBITS; - - for (i = 0, hdrpp = sorted_hdrs; i < count; i++, hdrpp++) + if ((s->flags & SEC_ALLOC) != 0) { - Elf_Internal_Shdr *hdr; + sections[i] = s; + ++i; + } + } + BFD_ASSERT (i <= bfd_count_sections (abfd)); + count = i; - hdr = *hdrpp; + qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections); - /* Ignore any section which will not be part of the process - image. */ - if ((hdr->sh_flags & SHF_ALLOC) == 0) - continue; - - /* Keep track of where this and the next sections go. - The section VMA must equal the file position modulo - the page size. */ - file_offset += (hdr->sh_addr - file_offset) % maxpagesize; - next_offset = file_offset; - if (hdr->sh_type != SHT_NOBITS) - next_offset = file_offset + hdr->sh_size; - - /* If this section fits in the segment we are constructing, add - it in. */ - if ((file_offset - (p_offset + p_memsz) - == hdr->sh_addr - (p_vaddr + p_memsz)) - && (last_type != SHT_NOBITS || hdr->sh_type == SHT_NOBITS)) - { - bfd_size_type adjust; + /* Build the mapping. */ - adjust = hdr->sh_addr - (p_vaddr + p_memsz); - p_memsz += hdr->sh_size + adjust; - file_offset = next_offset; - last_type = hdr->sh_type; - continue; - } + mfirst = NULL; + pm = &mfirst; - /* The section won't fit, start a new segment. */ - ++segs; + /* If we have a .interp section, then create a PT_PHDR segment for + the program headers and a PT_INTERP segment for the .interp + section. */ + 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))); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_PHDR; + /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */ + m->p_flags = PF_R | PF_X; + m->p_flags_valid = 1; + m->includes_phdrs = 1; + + *pm = m; + pm = &m->next; + + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_INTERP; + m->count = 1; + m->sections[0] = s; + + *pm = m; + pm = &m->next; + } + + /* Look through the sections. We put sections in the same program + segment when the start of the second section can be placed within + a few bytes of the end of the first section. */ + last_hdr = NULL; + phdr_index = 0; + maxpagesize = get_elf_backend_data (abfd)->maxpagesize; + writable = false; + dynsec = bfd_get_section_by_name (abfd, ".dynamic"); + if (dynsec != NULL + && (dynsec->flags & SEC_LOAD) == 0) + dynsec = NULL; + + /* Deal with -Ttext or something similar such that the + first section is not adjacent to the program headers. */ + if (count + && ((sections[0]->lma % maxpagesize) < + (elf_tdata (abfd)->program_header_size % maxpagesize))) + phdr_in_section = false; + + for (i = 0, hdrpp = sections; i < count; i++, hdrpp++) + { + asection *hdr; - /* Initialize the segment. */ - p_vaddr = hdr->sh_addr; - p_memsz = hdr->sh_size; - p_offset = file_offset; - file_offset = next_offset; + hdr = *hdrpp; - last_type = hdr->sh_type; + /* See if this section and the last one will fit in the same + segment. Don't put a loadable section after a non-loadable + section. If we are building a dynamic executable, don't put + a writable section in a read only segment (we don't do this + for a non-dynamic executable because some people prefer to + have only one program segment; anybody can use PHDRS in their + linker script to control what happens anyhow). */ + if (last_hdr == NULL + || ((BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize) + >= hdr->lma) + && ((last_hdr->flags & SEC_LOAD) != 0 + || (hdr->flags & SEC_LOAD) == 0) + && (dynsec == NULL + || writable + || (hdr->flags & SEC_READONLY) != 0))) + { + last_hdr = hdr; + continue; } - } - else - { - /* Assume we will need exactly two PT_LOAD segments: one for text - and one for data. */ - segs = 2; + + /* This section won't fit in the 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); + if (m == NULL) + goto error_return; + + *pm = m; + pm = &m->next; + + if ((hdr->flags & SEC_READONLY) == 0) + writable = true; + + last_hdr = hdr; + phdr_index = i; + phdr_in_section = false; } - s = bfd_get_section_by_name (abfd, ".interp"); - if (s != NULL && (s->flags & SEC_LOAD) != 0) + /* Create a final PT_LOAD program segment. */ + if (last_hdr != NULL) { - /* If we have a loadable interpreter section, we need a - PT_INTERP segment. In this case, assume we also need a - PT_PHDR segment, although that may not be true for all - targets. */ - segs += 2; + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section); + if (m == NULL) + goto error_return; + + *pm = m; + pm = &m->next; } - if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) + /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ + if (dynsec != NULL) { - /* We need a PT_DYNAMIC segment. */ - ++segs; + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_DYNAMIC; + m->count = 1; + m->sections[0] = dynsec; + + *pm = m; + pm = &m->next; } - /* Let the backend count up any program headers it might need. */ - if (bed->elf_backend_create_program_headers) - segs = ((*bed->elf_backend_create_program_headers) - (abfd, (Elf_Internal_Phdr *) NULL, segs)); + free (sections); + sections = NULL; - elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; - return elf_tdata (abfd)->program_header_size; + elf_tdata (abfd)->segment_map = mfirst; + return true; + + error_return: + if (sections != NULL) + free (sections); + return false; } -/* Create the program header. OFF is the file offset where the - program header should be written. FIRST is the first loadable ELF - section. SORTED_HDRS is the ELF sections sorted by section - address. PHDR_SIZE is the size of the program header as returned - by get_program_header_size. */ +/* Sort sections by VMA. */ -static file_ptr -map_program_segments (abfd, off, first, sorted_hdrs, phdr_size) - bfd *abfd; - file_ptr off; - Elf_Internal_Shdr *first; - Elf_Internal_Shdr **sorted_hdrs; - bfd_size_type phdr_size; +static int +elf_sort_sections (arg1, arg2) + const PTR arg1; + const PTR arg2; { - Elf_Internal_Phdr phdrs[10]; - unsigned int phdr_count; - Elf_Internal_Phdr *phdr; - int phdr_size_adjust; - unsigned int i; - Elf_Internal_Shdr **hdrpp; - asection *sinterp, *sdyn; - unsigned int last_type; - Elf_Internal_Ehdr *i_ehdrp; - struct elf_backend_data *bed = get_elf_backend_data (abfd); + const asection *sec1 = *(const asection **) arg1; + const asection *sec2 = *(const asection **) arg2; - BFD_ASSERT ((abfd->flags & (EXEC_P | DYNAMIC)) != 0); - BFD_ASSERT (phdr_size / sizeof (Elf_Internal_Phdr) - <= sizeof phdrs / sizeof (phdrs[0])); + if (sec1->vma < sec2->vma) + return -1; + else if (sec1->vma > sec2->vma) + return 1; - phdr_count = 0; - phdr = phdrs; + /* Put !SEC_LOAD sections after SEC_LOAD ones. */ - if (bed->want_hdr_in_seg) - phdr_size_adjust = first->sh_offset - phdr_size; - else - phdr_size_adjust = 0; +#define TOEND(x) (((x)->flags & SEC_LOAD) == 0) - /* If we have a loadable .interp section, we must create a PT_INTERP - segment which must precede all PT_LOAD segments. We assume that - we must also create a PT_PHDR segment, although that may not be - true for all targets. */ - sinterp = bfd_get_section_by_name (abfd, ".interp"); - if (sinterp != NULL && (sinterp->flags & SEC_LOAD) != 0) - { - BFD_ASSERT (first != NULL); + if (TOEND (sec1)) + if (TOEND (sec2)) + return sec1->target_index - sec2->target_index; + else + return 1; + + if (TOEND (sec2)) + return -1; - phdr->p_type = PT_PHDR; +#undef TOEND - phdr->p_offset = off; + /* Sort by size, to put zero sized sections before others at the + same address. */ - /* Account for any adjustment made because of the alignment of - the first loadable section. */ - phdr_size_adjust = (first->sh_offset - phdr_size) - off; - BFD_ASSERT (phdr_size_adjust >= 0 && phdr_size_adjust < 128); + if (sec1->_raw_size < sec2->_raw_size) + return -1; + if (sec1->_raw_size > sec2->_raw_size) + return 1; - /* The program header precedes all loadable sections. This lets - us compute its loadable address. This depends on the linker - script. */ - phdr->p_vaddr = first->sh_addr - (phdr_size + phdr_size_adjust); + return sec1->target_index - sec2->target_index; +} - phdr->p_paddr = first->bfd_section->lma - (phdr_size + phdr_size_adjust); - phdr->p_filesz = phdr_size; - phdr->p_memsz = phdr_size; +/* Assign file positions to the sections based on the mapping from + sections to segments. This function also sets up some fields in + the file header, and writes out the program headers. */ - /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */ - phdr->p_flags = PF_R | PF_X; +static boolean +assign_file_positions_for_segments (abfd) + bfd *abfd; +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + unsigned int count; + struct elf_segment_map *m; + unsigned int alloc; + Elf_Internal_Phdr *phdrs; + file_ptr off; + bfd_vma filehdr_vaddr, filehdr_paddr; + bfd_vma phdrs_vaddr, phdrs_paddr; + Elf_Internal_Phdr *p; + + if (elf_tdata (abfd)->segment_map == NULL) + { + if (! map_sections_to_segments (abfd)) + return false; + } - phdr->p_align = bed->s->file_align; - BFD_ASSERT ((phdr->p_vaddr - phdr->p_offset) % bed->s->file_align == 0); + if (bed->elf_backend_modify_segment_map) + { + if (! (*bed->elf_backend_modify_segment_map) (abfd)) + return false; + } - /* Include the ELF header in the first loadable segment. */ - phdr_size_adjust += off; + count = 0; + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + ++count; - ++phdr_count; - ++phdr; + elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr; + elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr; + elf_elfheader (abfd)->e_phnum = count; - phdr->p_type = PT_INTERP; - phdr->p_offset = sinterp->filepos; - phdr->p_vaddr = sinterp->vma; - phdr->p_paddr = sinterp->lma; - phdr->p_filesz = sinterp->_raw_size; - phdr->p_memsz = sinterp->_raw_size; - phdr->p_flags = PF_R; - phdr->p_align = 1 << bfd_get_section_alignment (abfd, sinterp); + if (count == 0) + return true; - ++phdr_count; - ++phdr; + /* If we already counted the number of program segments, make sure + that we allocated enough space. This happens when SIZEOF_HEADERS + is used in a linker script. */ + alloc = elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr; + if (alloc != 0 && count > alloc) + { + ((*_bfd_error_handler) + ("%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; } - /* Look through the sections to see how they will be divided into - program segments. The sections must be arranged in order by - sh_addr for this to work correctly. */ - phdr->p_type = PT_NULL; - last_type = SHT_PROGBITS; - for (i = 1, hdrpp = sorted_hdrs; - i < elf_elfheader (abfd)->e_shnum; - i++, hdrpp++) + if (alloc == 0) + alloc = count; + + phdrs = ((Elf_Internal_Phdr *) + bfd_alloc (abfd, alloc * sizeof (Elf_Internal_Phdr))); + if (phdrs == NULL) + return false; + + off = bed->s->sizeof_ehdr; + off += alloc * bed->s->sizeof_phdr; + + filehdr_vaddr = 0; + filehdr_paddr = 0; + phdrs_vaddr = 0; + phdrs_paddr = 0; + for (m = elf_tdata (abfd)->segment_map, p = phdrs; + m != NULL; + m = m->next, p++) { - Elf_Internal_Shdr *hdr; + unsigned int i; + asection **secpp; - hdr = *hdrpp; + /* If elf_segment_map is not from map_sections_to_segments, the + sections may not be correctly ordered. */ + if (m->count > 0) + qsort (m->sections, (size_t) m->count, sizeof (asection *), + elf_sort_sections); - /* Ignore any section which will not be part of the process - image. */ - if ((hdr->sh_flags & SHF_ALLOC) == 0) - continue; + p->p_type = m->p_type; - /* If this section fits in the segment we are constructing, add - it in. */ - if (phdr->p_type != PT_NULL - && (hdr->sh_offset - (phdr->p_offset + phdr->p_memsz) - == hdr->sh_addr - (phdr->p_vaddr + phdr->p_memsz)) - && (hdr->sh_addr - hdr->bfd_section->lma - == phdr->p_vaddr - phdr->p_paddr) - && (last_type != SHT_NOBITS || hdr->sh_type == SHT_NOBITS)) + if (m->p_flags_valid) + p->p_flags = m->p_flags; + else + p->p_flags = 0; + + if (p->p_type == PT_LOAD + && m->count > 0 + && (m->sections[0]->flags & SEC_LOAD) != 0) + off += (m->sections[0]->vma - off) % bed->maxpagesize; + + if (m->count == 0) + p->p_vaddr = 0; + else + p->p_vaddr = m->sections[0]->vma; + + if (m->p_paddr_valid) + p->p_paddr = m->p_paddr; + else if (m->count == 0) + p->p_paddr = 0; + else + p->p_paddr = m->sections[0]->lma; + + if (p->p_type == PT_LOAD) + p->p_align = bed->maxpagesize; + else if (m->count == 0) + p->p_align = bed->s->file_align; + else + p->p_align = 0; + + p->p_offset = 0; + p->p_filesz = 0; + p->p_memsz = 0; + + if (m->includes_filehdr) { - bfd_size_type adjust; - - adjust = hdr->sh_addr - (phdr->p_vaddr + phdr->p_memsz); - phdr->p_memsz += hdr->sh_size + adjust; - if (hdr->sh_type != SHT_NOBITS) - phdr->p_filesz += hdr->sh_size + adjust; - if ((hdr->sh_flags & SHF_WRITE) != 0) - phdr->p_flags |= PF_W; - if ((hdr->sh_flags & SHF_EXECINSTR) != 0) - phdr->p_flags |= PF_X; - last_type = hdr->sh_type; - continue; + if (! m->p_flags_valid) + p->p_flags |= PF_R; + p->p_offset = 0; + p->p_filesz = bed->s->sizeof_ehdr; + p->p_memsz = bed->s->sizeof_ehdr; + if (m->count > 0) + { + BFD_ASSERT (p->p_type == PT_LOAD); + p->p_vaddr -= off; + if (! m->p_paddr_valid) + p->p_paddr -= off; + } + if (p->p_type == PT_LOAD) + { + filehdr_vaddr = p->p_vaddr; + filehdr_paddr = p->p_paddr; + } + } + + if (m->includes_phdrs) + { + if (! m->p_flags_valid) + p->p_flags |= PF_R; + if (m->includes_filehdr) + { + if (p->p_type == PT_LOAD) + { + phdrs_vaddr = p->p_vaddr + bed->s->sizeof_ehdr; + phdrs_paddr = p->p_paddr + bed->s->sizeof_ehdr; + } + } + else + { + p->p_offset = bed->s->sizeof_ehdr; + if (m->count > 0) + { + BFD_ASSERT (p->p_type == PT_LOAD); + p->p_vaddr -= off - p->p_offset; + 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; + } + } + p->p_filesz += alloc * bed->s->sizeof_phdr; + p->p_memsz += alloc * bed->s->sizeof_phdr; } - /* The section won't fit, start a new segment. If we're already in one, - move to the next one. */ - if (phdr->p_type != PT_NULL) + if (p->p_type == PT_LOAD) { - ++phdr; - ++phdr_count; + if (! m->includes_filehdr && ! m->includes_phdrs) + p->p_offset = off; + else + { + file_ptr adjust; + + adjust = off - (p->p_offset + p->p_filesz); + p->p_filesz += adjust; + p->p_memsz += adjust; + } } - /* Initialize the segment. */ - phdr->p_type = PT_LOAD; - phdr->p_offset = hdr->sh_offset; - phdr->p_vaddr = hdr->sh_addr; - phdr->p_paddr = hdr->bfd_section->lma; - if (hdr->sh_type == SHT_NOBITS) - phdr->p_filesz = 0; - else - phdr->p_filesz = hdr->sh_size; - phdr->p_memsz = hdr->sh_size; - phdr->p_flags = PF_R; - if ((hdr->sh_flags & SHF_WRITE) != 0) - phdr->p_flags |= PF_W; - if ((hdr->sh_flags & SHF_EXECINSTR) != 0) - phdr->p_flags |= PF_X; - phdr->p_align = bed->maxpagesize; - - if (hdr == first - && (bed->want_hdr_in_seg - || (sinterp != NULL - && (sinterp->flags & SEC_LOAD) != 0))) + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) { - phdr->p_offset -= phdr_size + phdr_size_adjust; - phdr->p_vaddr -= phdr_size + phdr_size_adjust; - phdr->p_paddr -= phdr_size + phdr_size_adjust; - phdr->p_filesz += phdr_size + phdr_size_adjust; - phdr->p_memsz += phdr_size + phdr_size_adjust; + asection *sec; + flagword flags; + bfd_size_type align; + + sec = *secpp; + flags = sec->flags; + + if (p->p_type == PT_LOAD) + { + bfd_vma adjust; + + /* The section VMA must equal the file position modulo + the page size. */ + if ((flags & SEC_ALLOC) != 0) + { + adjust = (sec->vma - off) % bed->maxpagesize; + if (adjust != 0) + { + if (i == 0) + abort (); + p->p_memsz += adjust; + off += adjust; + if ((flags & SEC_LOAD) != 0) + p->p_filesz += adjust; + } + } + + sec->filepos = off; + + if ((flags & SEC_LOAD) != 0) + off += sec->_raw_size; + } + + p->p_memsz += sec->_raw_size; + + if ((flags & SEC_LOAD) != 0) + p->p_filesz += sec->_raw_size; + + align = 1 << bfd_get_section_alignment (abfd, sec); + if (align > p->p_align) + p->p_align = align; + + if (! m->p_flags_valid) + { + p->p_flags |= PF_R; + if ((flags & SEC_CODE) != 0) + p->p_flags |= PF_X; + if ((flags & SEC_READONLY) == 0) + p->p_flags |= PF_W; + } } + } - last_type = hdr->sh_type; + /* Now that we have set the section file positions, we can set up + the file positions for the non PT_LOAD segments. */ + for (m = elf_tdata (abfd)->segment_map, p = phdrs; + m != NULL; + m = m->next, p++) + { + if (p->p_type != PT_LOAD && m->count > 0) + { + BFD_ASSERT (! m->includes_filehdr && ! m->includes_phdrs); + p->p_offset = m->sections[0]->filepos; + } + if (m->count == 0) + { + if (m->includes_filehdr) + { + p->p_vaddr = filehdr_vaddr; + if (! m->p_paddr_valid) + p->p_paddr = filehdr_paddr; + } + else if (m->includes_phdrs) + { + p->p_vaddr = phdrs_vaddr; + if (! m->p_paddr_valid) + p->p_paddr = phdrs_paddr; + } + } } - if (phdr->p_type != PT_NULL) + /* Clear out any program headers we allocated but did not use. */ + for (; count < alloc; count++, p++) { - ++phdr; - ++phdr_count; + memset (p, 0, sizeof *p); + p->p_type = PT_NULL; } - /* If we have a .dynamic section, create a PT_DYNAMIC segment. */ - sdyn = bfd_get_section_by_name (abfd, ".dynamic"); - if (sdyn != NULL && (sdyn->flags & SEC_LOAD) != 0) + elf_tdata (abfd)->phdr = phdrs; + + elf_tdata (abfd)->next_file_pos = off; + + /* Write out the program headers. */ + if (bfd_seek (abfd, bed->s->sizeof_ehdr, SEEK_SET) != 0 + || bed->s->write_out_phdrs (abfd, phdrs, alloc) != 0) + return false; + + return true; +} + +/* Get the size of the program header. + + If this is called by the linker before any of the section VMA's are set, it + can't calculate the correct value for a strange memory layout. This only + happens when SIZEOF_HEADERS is used in a linker script. In this case, + SORTED_HDRS is NULL and we assume the normal scenario of one text and one + data segment (exclusive of .interp and .dynamic). + + ??? User written scripts must either not use SIZEOF_HEADERS, or assume there + will be two segments. */ + +static bfd_size_type +get_program_header_size (abfd) + bfd *abfd; +{ + size_t segs; + asection *s; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + /* We can't return a different result each time we're called. */ + if (elf_tdata (abfd)->program_header_size != 0) + return elf_tdata (abfd)->program_header_size; + + if (elf_tdata (abfd)->segment_map != NULL) { - phdr->p_type = PT_DYNAMIC; - phdr->p_offset = sdyn->filepos; - phdr->p_vaddr = sdyn->vma; - phdr->p_paddr = sdyn->lma; - phdr->p_filesz = sdyn->_raw_size; - phdr->p_memsz = sdyn->_raw_size; - phdr->p_flags = PF_R; - if ((sdyn->flags & SEC_READONLY) == 0) - phdr->p_flags |= PF_W; - if ((sdyn->flags & SEC_CODE) != 0) - phdr->p_flags |= PF_X; - phdr->p_align = 1 << bfd_get_section_alignment (abfd, sdyn); + struct elf_segment_map *m; - ++phdr; - ++phdr_count; + segs = 0; + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + ++segs; + elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; + return elf_tdata (abfd)->program_header_size; } - /* Let the backend create additional program headers. */ - if (bed->elf_backend_create_program_headers) - phdr_count = (*bed->elf_backend_create_program_headers) (abfd, - phdrs, - phdr_count); + /* Assume we will need exactly two PT_LOAD segments: one for text + and one for data. */ + segs = 2; - /* Make sure the return value from get_program_header_size matches - what we computed here. Actually, it's OK if we allocated too - much space in the program header. */ - if (phdr_count > phdr_size / bed->s->sizeof_phdr) + s = bfd_get_section_by_name (abfd, ".interp"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) { - ((*_bfd_error_handler) - ("%s: Not enough room for program headers (allocated %lu, need %u)", - bfd_get_filename (abfd), - (unsigned long) (phdr_size / bed->s->sizeof_phdr), - phdr_count)); - bfd_set_error (bfd_error_bad_value); - return (file_ptr) -1; + /* If we have a loadable interpreter section, we need a + PT_INTERP segment. In this case, assume we also need a + PT_PHDR segment, although that may not be true for all + targets. */ + segs += 2; } - /* Set up program header information. */ - i_ehdrp = elf_elfheader (abfd); - i_ehdrp->e_phentsize = bed->s->sizeof_phdr; - i_ehdrp->e_phoff = off; - i_ehdrp->e_phnum = phdr_count; - - /* Save the program headers away. I don't think anybody uses this - information right now. */ - elf_tdata (abfd)->phdr = ((Elf_Internal_Phdr *) - bfd_alloc (abfd, - (phdr_count - * sizeof (Elf_Internal_Phdr)))); - if (elf_tdata (abfd)->phdr == NULL && phdr_count != 0) + if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) { - bfd_set_error (bfd_error_no_memory); - return (file_ptr) -1; + /* We need a PT_DYNAMIC segment. */ + ++segs; } - memcpy (elf_tdata (abfd)->phdr, phdrs, - phdr_count * sizeof (Elf_Internal_Phdr)); - /* Write out the program headers. */ - if (bfd_seek (abfd, off, SEEK_SET) != 0) - return (file_ptr) -1; + /* Let the backend count up any program headers it might need. */ + if (bed->elf_backend_additional_program_headers) + { + int a; - if (bed->s->write_out_phdrs (abfd, phdrs, phdr_count) != 0) - return (file_ptr) -1; + a = (*bed->elf_backend_additional_program_headers) (abfd); + if (a == -1) + abort (); + segs += a; + } - return off + phdr_count * bed->s->sizeof_phdr; + elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; + return elf_tdata (abfd)->program_header_size; } /* Work out the file positions of all the sections. This is called by @@ -1862,8 +2232,6 @@ map_program_segments (abfd, off, first, sorted_hdrs, phdr_size) We also don't set the positions of the .symtab and .strtab here. */ -static int elf_sort_hdrs PARAMS ((const PTR, const PTR)); - static boolean assign_file_positions_except_relocs (abfd) bfd *abfd; @@ -1874,14 +2242,14 @@ assign_file_positions_except_relocs (abfd) file_ptr off; struct elf_backend_data *bed = get_elf_backend_data (abfd); - /* Start after the ELF header. */ - off = i_ehdrp->e_ehsize; - if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) { Elf_Internal_Shdr **hdrpp; unsigned int i; + /* Start after the ELF header. */ + off = i_ehdrp->e_ehsize; + /* We are not creating an executable, which means that we are not creating a program header, and that the actual order of the sections in the file is unimportant. */ @@ -1907,96 +2275,45 @@ assign_file_positions_except_relocs (abfd) } else { - file_ptr phdr_off; - bfd_size_type phdr_size; - bfd_vma maxpagesize; - size_t hdrppsize; - Elf_Internal_Shdr **sorted_hdrs; - Elf_Internal_Shdr **hdrpp; unsigned int i; - Elf_Internal_Shdr *first; - file_ptr phdr_map; - - /* We are creating an executable. */ - - maxpagesize = get_elf_backend_data (abfd)->maxpagesize; - if (maxpagesize == 0) - maxpagesize = 1; - - /* We must sort the sections. The GNU linker will always create - the sections in an appropriate order, but the Irix 5 linker - will not. We don't include the dummy first section in the - sort. We sort sections which are not SHF_ALLOC to the end. */ - hdrppsize = (i_ehdrp->e_shnum - 1) * sizeof (Elf_Internal_Shdr *); - sorted_hdrs = (Elf_Internal_Shdr **) malloc (hdrppsize); - if (sorted_hdrs == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + Elf_Internal_Shdr **hdrpp; - memcpy (sorted_hdrs, i_shdrpp + 1, hdrppsize); - qsort (sorted_hdrs, (size_t) i_ehdrp->e_shnum - 1, - sizeof (Elf_Internal_Shdr *), elf_sort_hdrs); - - /* We can't actually create the program header until we have set the - file positions for the sections, and we can't do that until we know - how big the header is going to be. */ - off = align_file_position (off, bed->s->file_align); - phdr_size = get_program_header_size (abfd, - sorted_hdrs, i_ehdrp->e_shnum - 1, - maxpagesize); - if (phdr_size == (bfd_size_type) -1) + /* Assign file positions for the loaded sections based on the + assignment of sections to segments. */ + if (! assign_file_positions_for_segments (abfd)) return false; - /* Compute the file offsets of each section. */ - phdr_off = off; - off += phdr_size; - first = NULL; - for (i = 1, hdrpp = sorted_hdrs; i < i_ehdrp->e_shnum; i++, hdrpp++) + /* Assign file positions for the other sections. */ + + off = elf_tdata (abfd)->next_file_pos; + for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++) { Elf_Internal_Shdr *hdr; hdr = *hdrpp; - if ((hdr->sh_flags & SHF_ALLOC) == 0) + if (hdr->bfd_section != NULL + && hdr->bfd_section->filepos != 0) + hdr->sh_offset = hdr->bfd_section->filepos; + else if ((hdr->sh_flags & SHF_ALLOC) != 0) { - if (hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) - { - hdr->sh_offset = -1; - continue; - } - if (hdr == i_shdrpp[tdata->symtab_section] - || hdr == i_shdrpp[tdata->strtab_section]) - { - hdr->sh_offset = -1; - continue; - } - off = _bfd_elf_assign_file_position_for_section (hdr, off, - true); - } - else - { - if (first == NULL) - first = hdr; - - /* The section VMA must equal the file position modulo - the page size. This is required by the program - header. */ - off += (hdr->sh_addr - off) % maxpagesize; + ((*_bfd_error_handler) + ("%s: warning: allocated section `%s' not in segment", + bfd_get_filename (abfd), + (hdr->bfd_section == NULL + ? "*unknown*" + : hdr->bfd_section->name))); + off += (hdr->sh_addr - off) % bed->maxpagesize; off = _bfd_elf_assign_file_position_for_section (hdr, off, false); } - } - - /* Create the program header. */ - phdr_map = map_program_segments (abfd, phdr_off, first, sorted_hdrs, - phdr_size); - if (phdr_map == (file_ptr) -1) - return false; - BFD_ASSERT ((bfd_size_type) phdr_map - <= (bfd_size_type) phdr_off + phdr_size); - - free (sorted_hdrs); + else if (hdr->sh_type == SHT_REL + || hdr->sh_type == SHT_RELA + || hdr == i_shdrpp[tdata->symtab_section] + || hdr == i_shdrpp[tdata->strtab_section]) + hdr->sh_offset = -1; + else + off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + } } /* Place the section headers. */ @@ -2009,47 +2326,6 @@ assign_file_positions_except_relocs (abfd) return true; } -/* Sort the ELF headers by VMA. We sort headers which are not - SHF_ALLOC to the end. */ -static int -elf_sort_hdrs (arg1, arg2) - const PTR arg1; - const PTR arg2; -{ - int ret; - const Elf_Internal_Shdr *hdr1 = *(const Elf_Internal_Shdr **) arg1; - const Elf_Internal_Shdr *hdr2 = *(const Elf_Internal_Shdr **) arg2; - -#define TOEND(x) (((x)->sh_flags & SHF_ALLOC)==0) - - if (TOEND (hdr1)) - if (TOEND (hdr2)) - return 0; - else - return 1; - - if (TOEND (hdr2)) - return -1; - - if (hdr1->sh_addr < hdr2->sh_addr) - return -1; - else if (hdr1->sh_addr > hdr2->sh_addr) - return 1; - - /* Put !SHT_NOBITS sections before SHT_NOBITS ones. - The main loop in map_program_segments requires this. */ - - ret = (hdr1->sh_type == SHT_NOBITS) - (hdr2->sh_type == SHT_NOBITS); - - if (ret != 0) - return ret; - if (hdr1->sh_size < hdr2->sh_size) - return -1; - if (hdr1->sh_size > hdr2->sh_size) - return 1; - return 0; -} - static boolean prep_headers (abfd) bfd *abfd; @@ -2077,7 +2353,7 @@ prep_headers (abfd) i_ehdrp->e_ident[EI_CLASS] = bed->s->elfclass; i_ehdrp->e_ident[EI_DATA] = - abfd->xvec->byteorder_big_p ? ELFDATA2MSB : ELFDATA2LSB; + bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB; i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current; for (count = EI_PAD; count < EI_NIDENT; count++) @@ -2295,13 +2571,15 @@ _bfd_elf_section_from_bfd_section (abfd, asect) return -1; } -/* given a symbol, return the bfd index for that symbol. */ - int +/* Given a BFD symbol, return the index in the ELF symbol table, or -1 + on error. */ + +int _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) bfd *abfd; - struct symbol_cache_entry **asym_ptr_ptr; + asymbol **asym_ptr_ptr; { - struct symbol_cache_entry *asym_ptr = *asym_ptr_ptr; + asymbol *asym_ptr = *asym_ptr_ptr; int idx; flagword flags = asym_ptr->flags; @@ -2325,13 +2603,24 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) } idx = asym_ptr->udata.i; - BFD_ASSERT (idx != 0); + + if (idx == 0) + { + /* 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)); + bfd_set_error (bfd_error_no_symbols); + return -1; + } #if DEBUG & 4 { fprintf (stderr, "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)); + (long) asym_ptr, asym_ptr->name, idx, flags, + elf_symbol_flags (flags)); fflush (stderr); } #endif @@ -2339,6 +2628,111 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) return idx; } +/* Copy private BFD data. This copies any program header information. */ + +static boolean +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; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + if (elf_tdata (ibfd)->phdr == NULL) + return true; + + iehdr = elf_elfheader (ibfd); + + mfirst = NULL; + pm = &mfirst; + + c = elf_elfheader (ibfd)->e_phnum; + for (i = 0, p = elf_tdata (ibfd)->phdr; i < c; i++, p++) + { + 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) + 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; + + m->includes_filehdr = (p->p_offset == 0 + && p->p_filesz >= iehdr->e_ehsize); + + 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))); + + 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) + { + m->sections[isec] = s->output_section; + ++isec; + } + } + BFD_ASSERT (isec == csecs); + m->count = csecs; + + *pm = m; + pm = &m->next; + } + + elf_tdata (obfd)->segment_map = mfirst; + + return true; +} + /* Copy private section information. This copies over the entsize field, and sometimes the info field. */ @@ -2355,6 +2749,28 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec) || obfd->xvec->flavour != bfd_target_elf_flavour) return true; + /* Copy over private BFD data if it has not already been copied. + This must be done here, rather than in the copy_private_bfd_data + entry point, because the latter is called after the section + contents have been set, which means that the program headers have + already been worked out. */ + if (elf_tdata (obfd)->segment_map == NULL + && elf_tdata (ibfd)->phdr != NULL) + { + 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) + break; + if (s == NULL) + { + if (! copy_private_bfd_data (ibfd, obfd)) + return false; + } + } + ihdr = &elf_section_data (isec)->this_hdr; ohdr = &elf_section_data (osec)->this_hdr; @@ -2450,10 +2866,7 @@ swap_out_syms (abfd, sttp) outbound_syms = bfd_alloc (abfd, (1 + symcount) * bed->s->sizeof_sym); if (outbound_syms == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; symtab_hdr->contents = (PTR) outbound_syms; /* now generate the data (for "contents") */ @@ -2475,6 +2888,7 @@ swap_out_syms (abfd, sttp) bfd_vma value = syms[idx]->value; elf_symbol_type *type_ptr; flagword flags = syms[idx]->flags; + int type; if (flags & BSF_SECTION_SYM) /* Section symbols have no names. */ @@ -2569,15 +2983,20 @@ swap_out_syms (abfd, sttp) sym.st_shndx = shndx; } + if ((flags & BSF_FUNCTION) != 0) + type = STT_FUNC; + else if ((flags & BSF_OBJECT) != 0) + type = STT_OBJECT; + else + type = STT_NOTYPE; + if (bfd_is_com_section (syms[idx]->section)) - sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT); + 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), - ((flags & BSF_FUNCTION) - ? STT_FUNC - : STT_NOTYPE)); + type); else if (flags & BSF_SECTION_SYM) sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); else if (flags & BSF_FILE) @@ -2585,7 +3004,6 @@ swap_out_syms (abfd, sttp) else { int bind = STB_LOCAL; - int type = STT_OBJECT; if (flags & BSF_LOCAL) bind = STB_LOCAL; @@ -2594,9 +3012,6 @@ swap_out_syms (abfd, sttp) else if (flags & BSF_GLOBAL) bind = STB_GLOBAL; - if (flags & BSF_FUNCTION) - type = STT_FUNC; - sym.st_info = ELF_ST_INFO (bind, type); } @@ -2720,10 +3135,7 @@ _bfd_elf_make_empty_symbol (abfd) newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (elf_symbol_type)); if (!newsym) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } + return NULL; else { newsym->symbol.the_bfd = abfd; @@ -2784,15 +3196,26 @@ _bfd_elf_find_nearest_line (abfd, 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; for (p = symbols; *p != NULL; p++) { @@ -2811,9 +3234,13 @@ _bfd_elf_find_nearest_line (abfd, filename = bfd_asymbol_name (&q->symbol); break; case STT_FUNC: - if (func == NULL - || q->symbol.value <= offset) - func = (asymbol *) q; + if (q->symbol.section == section + && q->symbol.value >= low_func + && q->symbol.value <= offset) + { + func = (asymbol *) q; + low_func = q->symbol.value; + } break; } } @@ -2836,8 +3263,7 @@ _bfd_elf_sizeof_headers (abfd, reloc) ret = get_elf_backend_data (abfd)->s->sizeof_ehdr; if (! reloc) - ret += get_program_header_size (abfd, (Elf_Internal_Shdr **) NULL, 0, - (bfd_vma) 0); + ret += get_program_header_size (abfd); return ret; } @@ -2885,3 +3311,101 @@ _bfd_elf_no_info_to_howto_rel (abfd, cache_ptr, dst) abort (); } #endif + +/* Try to convert a non-ELF reloc into an ELF one. */ + +boolean +_bfd_elf_validate_reloc (abfd, areloc) + bfd *abfd; + arelent *areloc; +{ + /* Check whether we really have an ELF howto. */ + + 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. */ + + if (areloc->howto->pc_relative) + { + switch (areloc->howto->bitsize) + { + case 8: + code = BFD_RELOC_8_PCREL; + break; + case 12: + code = BFD_RELOC_12_PCREL; + break; + case 16: + code = BFD_RELOC_16_PCREL; + break; + case 24: + code = BFD_RELOC_24_PCREL; + break; + case 32: + code = BFD_RELOC_32_PCREL; + break; + case 64: + code = BFD_RELOC_64_PCREL; + break; + default: + goto fail; + } + + howto = bfd_reloc_type_lookup (abfd, code); + + if (areloc->howto->pcrel_offset != howto->pcrel_offset) + { + if (howto->pcrel_offset) + areloc->addend += areloc->address; + else + areloc->addend -= areloc->address; /* addend is unsigned!! */ + } + } + else + { + switch (areloc->howto->bitsize) + { + case 8: + code = BFD_RELOC_8; + break; + case 14: + code = BFD_RELOC_14; + break; + case 16: + code = BFD_RELOC_16; + break; + case 26: + code = BFD_RELOC_26; + break; + case 32: + code = BFD_RELOC_32; + break; + case 64: + code = BFD_RELOC_64; + break; + default: + goto fail; + } + + howto = bfd_reloc_type_lookup (abfd, code); + } + + if (howto) + areloc->howto = howto; + else + goto fail; + } + + return true; + + fail: + (*_bfd_error_handler) + ("%s: unsupported relocation type %s", + bfd_get_filename (abfd), areloc->howto->name); + bfd_set_error (bfd_error_bad_value); + return false; +} -- cgit v1.2.3