diff options
-rw-r--r-- | bfd/ChangeLog | 10 | ||||
-rw-r--r-- | bfd/elf.c | 191 | ||||
-rw-r--r-- | binutils/ChangeLog | 6 | ||||
-rw-r--r-- | binutils/readelf.c | 19 | ||||
-rw-r--r-- | include/elf/ChangeLog | 6 | ||||
-rw-r--r-- | include/elf/internal.h | 25 |
6 files changed, 229 insertions, 28 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c943726..6ba2531 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,4 +1,12 @@ -2006-01-26 Nathan Sidwell <nathan@codesourcery.com> +2006-02-10 H.J. Lu <hongjiu.lu@intel.com> + + PR binutils/2258 + * elf.c (copy_private_bfd_data): Renamed to ... + (rewrite_elf_program_header): This. + (copy_elf_program_header): New function. + (copy_private_bfd_data): Likewise. + +2006-02-07 Nathan Sidwell <nathan@codesourcery.com> * archures.c (bfd_mach_mcf5200, bfd_mach_mcf5206e, bfd_mach_mcf5307, bfd_mach_mcf5407, bfd_mach_mcf528x, @@ -5045,10 +5045,10 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr) return idx; } -/* Copy private BFD data. This copies any program header information. */ +/* Rewrite program header information. */ static bfd_boolean -copy_private_bfd_data (bfd *ibfd, bfd *obfd) +rewrite_elf_program_header (bfd *ibfd, bfd *obfd) { Elf_Internal_Ehdr *iehdr; struct elf_segment_map *map; @@ -5064,13 +5064,6 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) unsigned int phdr_adjust_num = 0; const struct elf_backend_data *bed; - 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; - bed = get_elf_backend_data (ibfd); iehdr = elf_elfheader (ibfd); @@ -5630,6 +5623,186 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) return TRUE; } +/* Copy ELF program header information. */ + +static bfd_boolean +copy_elf_program_header (bfd *ibfd, bfd *obfd) +{ + 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; + unsigned int i; + unsigned int num_segments; + bfd_boolean phdr_included = FALSE; + + iehdr = elf_elfheader (ibfd); + + map_first = NULL; + pointer_to_map = &map_first; + + num_segments = elf_elfheader (ibfd)->e_phnum; + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i++, segment++) + { + asection *section; + unsigned int section_count; + bfd_size_type amt; + Elf_Internal_Shdr *this_hdr; + + /* FIXME: Do we need to copy PT_NULL segment? */ + if (segment->p_type == PT_NULL) + continue; + + /* Compute how many sections are in this segment. */ + for (section = ibfd->sections, section_count = 0; + section != NULL; + section = section->next) + { + this_hdr = &(elf_section_data(section)->this_hdr); + if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) + section_count++; + } + + /* Allocate a segment map big enough to contain + all of the sections we have selected. */ + amt = sizeof (struct elf_segment_map); + if (section_count != 0) + amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); + map = bfd_alloc (obfd, amt); + if (map == NULL) + return FALSE; + + /* Initialize the fields of the output segment map with the + input segment. */ + 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) + { + unsigned int isec = 0; + + for (section = ibfd->sections; + section != NULL; + section = section->next) + { + this_hdr = &(elf_section_data(section)->this_hdr); + if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) + map->sections[isec++] = section->output_section; + } + } + + map->count = section_count; + *pointer_to_map = map; + pointer_to_map = &map->next; + } + + elf_tdata (obfd)->segment_map = map_first; + return TRUE; +} + +/* Copy private BFD data. This copies or rewrites ELF program header + information. */ + +static bfd_boolean +copy_private_bfd_data (bfd *ibfd, bfd *obfd) +{ + Elf_Internal_Phdr *segment; + + 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; + + if (ibfd->xvec == obfd->xvec) + { + /* Check if any sections in the input BFD covered by ELF program + header are changed. */ + asection *section, *osec; + unsigned int i, num_segments; + Elf_Internal_Shdr *this_hdr; + + /* Initialize the segment mark field. */ + for (section = obfd->sections; section != NULL; + section = section->next) + section->segment_mark = FALSE; + + num_segments = elf_elfheader (ibfd)->e_phnum; + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i++, segment++) + { + for (section = ibfd->sections; + section != NULL; section = section->next) + { + /* We mark the output section so that we know it comes + from the input BFD. */ + osec = section->output_section; + if (osec) + osec->segment_mark = TRUE; + + /* Check if this section is covered by the segment. */ + this_hdr = &(elf_section_data(section)->this_hdr); + if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) + { + /* FIXME: Check if its output section is changed or + removed. What else do we need to check? */ + if (osec == NULL + || section->flags != osec->flags + || section->lma != osec->lma + || section->vma != osec->vma + || section->size != osec->size + || section->rawsize != osec->rawsize + || section->alignment_power != osec->alignment_power) + goto rewrite; + } + } + } + + /* Check to see if any output section doesn't come from the + input BFD. */ + for (section = obfd->sections; section != NULL; + section = section->next) + { + if (section->segment_mark == FALSE) + goto rewrite; + else + section->segment_mark = FALSE; + } + + return copy_elf_program_header (ibfd, obfd); + } + +rewrite: + return rewrite_elf_program_header (ibfd, obfd); +} + /* Initialize private output section information from input section. */ bfd_boolean diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 982523a..90257f8 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,9 @@ +2006-02-10 H.J. Lu <hongjiu.lu@intel.com> + + PR binutils/2258 + * readelf.c (process_program_headers): Use + ELF_IS_SECTION_IN_SEGMENT_MEMORY. + 2006-02-09 Eric Botcazou <ebotcazou@libertysurf.fr> * configure.in (CHECK_DECLS): Add snprintf and vsnprintf. diff --git a/binutils/readelf.c b/binutils/readelf.c index a10dc41..208b6d4 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -3447,24 +3447,7 @@ process_program_headers (FILE *file) for (j = 1; j < elf_header.e_shnum; j++, section++) { - if (section->sh_size > 0 - /* PT_TLS segment contains only SHF_TLS sections. */ - && (segment->p_type != PT_TLS - || (section->sh_flags & SHF_TLS) != 0) - /* Compare allocated sections by VMA, unallocated - sections by file offset. */ - && (section->sh_flags & SHF_ALLOC - ? (section->sh_addr >= segment->p_vaddr - && section->sh_addr + section->sh_size - <= segment->p_vaddr + segment->p_memsz) - : ((bfd_vma) section->sh_offset >= segment->p_offset - && (section->sh_offset + section->sh_size - <= segment->p_offset + segment->p_filesz))) - /* .tbss is special. It doesn't contribute memory space - to normal segments. */ - && (!((section->sh_flags & SHF_TLS) != 0 - && section->sh_type == SHT_NOBITS) - || segment->p_type == PT_TLS)) + if (ELF_IS_SECTION_IN_SEGMENT_MEMORY(section, segment)) printf ("%s ", SECTION_NAME (section)); } diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index fca9b33..bd14181 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,9 @@ +2006-02-10 H.J. Lu <hongjiu.lu@intel.com> + + PR binutils/2258 + * internal.h (ELF_IS_SECTION_IN_SEGMENT_FILE): New. + (ELF_IS_SECTION_IN_SEGMENT_MEMORY): Likewise. + 2006-02-07 Nathan Sidwell <nathan@codesourcery.com> * m68k.h (EF_CPU32, EF_M68000, EF_CFV4E): Rename to ... diff --git a/include/elf/internal.h b/include/elf/internal.h index 7e13d54..e4eba7d 100644 --- a/include/elf/internal.h +++ b/include/elf/internal.h @@ -251,4 +251,29 @@ struct elf_segment_map asection *sections[1]; }; +/* Decide if the given sec_hdr is in the given segment in file. */ +#define ELF_IS_SECTION_IN_SEGMENT_FILE(sec_hdr, segment) \ + (sec_hdr->sh_size > 0 \ + /* PT_TLS segment contains only SHF_TLS sections. */ \ + && (segment->p_type != PT_TLS \ + || (sec_hdr->sh_flags & SHF_TLS) != 0) \ + /* Compare allocated sec_hdrs by VMA, unallocated sec_hdrs \ + by file offset. */ \ + && (sec_hdr->sh_flags & SHF_ALLOC \ + ? (sec_hdr->sh_addr >= segment->p_vaddr \ + && sec_hdr->sh_addr + sec_hdr->sh_size \ + <= segment->p_vaddr + segment->p_memsz) \ + : ((bfd_vma) sec_hdr->sh_offset >= segment->p_offset \ + && (sec_hdr->sh_offset + sec_hdr->sh_size \ + <= segment->p_offset + segment->p_filesz)))) + +/* Decide if the given sec_hdr is in the given segment in memory. */ +#define ELF_IS_SECTION_IN_SEGMENT_MEMORY(sec_hdr, segment) \ + (ELF_IS_SECTION_IN_SEGMENT_FILE (sec_hdr, segment) \ + /* .tbss is special. It doesn't contribute memory space to \ + normal segments. */ \ + && (!((sec_hdr->sh_flags & SHF_TLS) != 0 \ + && sec_hdr->sh_type == SHT_NOBITS) \ + || segment->p_type == PT_TLS)) + #endif /* _ELF_INTERNAL_H */ |