From cfcac11dc826f830a5ca9a7265ad5e2ecd14e92f Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Wed, 9 Sep 2009 15:03:54 +0000 Subject: [PATCH] PR 10478: * elf.c (bfd_section_from_shdr): Do not reject sparc binaries with section headers containing sh_link values of SHN_BEFORE or SHN_AFTER. * elfcode.h (elf_object_p): Likewise. readelf.c (get_elf_section_flags): Add support for SHF_EXCLUDE and SHF_ORDERED. (process_section_headers): Warn about out of range sh_link values. When displaying detailed section header information annote the SHN_BEFORE and SHN_AFTER values. --- bfd/ChangeLog | 9 +++- bfd/elf.c | 20 +++++++-- bfd/elfcode.h | 18 +++++++- binutils/ChangeLog | 9 ++++ binutils/readelf.c | 105 ++++++++++++++++++++++++++++++++++----------- 5 files changed, 130 insertions(+), 31 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 39ee6fd19a2..82a663bf916 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2009-09-09 Nick Clifton + + PR 10478: + * elf.c (bfd_section_from_shdr): Do not reject sparc binaries with + section headers containing sh_link values of SHN_BEFORE or + SHN_AFTER. + * elfcode.h (elf_object_p): Likewise. + 2009-09-09 Tristan Gingold Handle DYLD_INFO introduced by Darwin10. @@ -12,7 +20,6 @@ (bfd_mach_o_load_command_name): AddB FD_MACH_O_LC_DYLD_INFO. (bfd_mach_o_print_dyld_info): New function. - 2009-09-09 M R Swami Reddy * elf32-cr16.c (elf32_cr16_relocate_section): Add code to discard the diff --git a/bfd/elf.c b/bfd/elf.c index 13f690465ee..ed974c0176b 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1514,10 +1514,24 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) case SHT_DYNAMIC: /* Dynamic linking information. */ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) return FALSE; - if (hdr->sh_link > elf_numsections (abfd) - || elf_elfsections (abfd)[hdr->sh_link] == NULL) + if (hdr->sh_link > elf_numsections (abfd)) + { + /* PR 10478: Accept sparc binaries with a sh_link + field set to SHN_BEFORE or SHN_AFTER. */ + switch (bfd_get_arch (abfd)) + { + case bfd_arch_sparc: + if (hdr->sh_link == (SHN_LORESERVE & 0xffff) /* SHN_BEFORE */ + || hdr->sh_link == ((SHN_LORESERVE + 1) & 0xffff) /* SHN_AFTER */) + break; + /* Otherwise fall through. */ + default: + return FALSE; + } + } + else if (elf_elfsections (abfd)[hdr->sh_link] == NULL) return FALSE; - if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB) + else if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB) { Elf_Internal_Shdr *dynsymhdr; diff --git a/bfd/elfcode.h b/bfd/elfcode.h index 10aa13140e7..889d25ab736 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -760,7 +760,23 @@ elf_object_p (bfd *abfd) /* Sanity check sh_link and sh_info. */ if (i_shdrp[shindex].sh_link >= num_sec) - goto got_wrong_format_error; + { + /* PR 10478: Accept sparc binaries with a sh_link + field set to SHN_BEFORE or SHN_AFTER. */ + switch (ebd->elf_machine_code) + { + case EM_OLD_SPARCV9: + case EM_SPARC32PLUS: + case EM_SPARCV9: + case EM_SPARC: + if (i_shdrp[shindex].sh_link == (SHN_LORESERVE & 0xffff) /* SHN_BEFORE */ + || i_shdrp[shindex].sh_link == ((SHN_LORESERVE + 1) & 0xffff) /* SHN_AFTER */) + break; + /* Otherwise fall through. */ + default: + goto got_wrong_format_error; + } + } if (((i_shdrp[shindex].sh_flags & SHF_INFO_LINK) || i_shdrp[shindex].sh_type == SHT_RELA diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 1722fe7ee83..022cda57339 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,12 @@ +2009-09-09 Nick Clifton + + PR 10478: + readelf.c (get_elf_section_flags): Add support for SHF_EXCLUDE and + SHF_ORDERED. + (process_section_headers): Warn about out of range sh_link + values. When displaying detailed section header information + annote the SHN_BEFORE and SHN_AFTER values. + 2009-09-08 Alan Modra * dwarf.c (byte_get_little_endian): Handle size of 3. diff --git a/binutils/readelf.c b/binutils/readelf.c index 590c70d5a38..872ec0900ce 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -3873,26 +3873,29 @@ get_elf_section_flags (bfd_vma sh_flags) } flags [] = { - { "WRITE", 5 }, - { "ALLOC", 5 }, - { "EXEC", 4 }, - { "MERGE", 5 }, - { "STRINGS", 7 }, - { "INFO LINK", 9 }, - { "LINK ORDER", 10 }, - { "OS NONCONF", 10 }, - { "GROUP", 5 }, - { "TLS", 3 }, - /* IA-64 specific. */ - { "SHORT", 5 }, - { "NORECOV", 7 }, - /* IA-64 OpenVMS specific. */ - { "VMS_GLOBAL", 10 }, - { "VMS_OVERLAID", 12 }, - { "VMS_SHARED", 10 }, - { "VMS_VECTOR", 10 }, - { "VMS_ALLOC_64BIT", 15 }, - { "VMS_PROTECTED", 13} + /* 0 */ { STRING_COMMA_LEN ("WRITE") }, + /* 1 */ { STRING_COMMA_LEN ("ALLOC") }, + /* 2 */ { STRING_COMMA_LEN ("EXEC") }, + /* 3 */ { STRING_COMMA_LEN ("MERGE") }, + /* 4 */ { STRING_COMMA_LEN ("STRINGS") }, + /* 5 */ { STRING_COMMA_LEN ("INFO LINK") }, + /* 6 */ { STRING_COMMA_LEN ("LINK ORDER") }, + /* 7 */ { STRING_COMMA_LEN ("OS NONCONF") }, + /* 8 */ { STRING_COMMA_LEN ("GROUP") }, + /* 9 */ { STRING_COMMA_LEN ("TLS") }, + /* IA-64 specific. */ + /* 10 */ { STRING_COMMA_LEN ("SHORT") }, + /* 11 */ { STRING_COMMA_LEN ("NORECOV") }, + /* IA-64 OpenVMS specific. */ + /* 12 */ { STRING_COMMA_LEN ("VMS_GLOBAL") }, + /* 13 */ { STRING_COMMA_LEN ("VMS_OVERLAID") }, + /* 14 */ { STRING_COMMA_LEN ("VMS_SHARED") }, + /* 15 */ { STRING_COMMA_LEN ("VMS_VECTOR") }, + /* 16 */ { STRING_COMMA_LEN ("VMS_ALLOC_64BIT") }, + /* 17 */ { STRING_COMMA_LEN ("VMS_PROTECTED") }, + /* SPARC specific. */ + /* 18 */ { STRING_COMMA_LEN ("EXCLUDE") }, + /* 19 */ { STRING_COMMA_LEN ("ORDERED") } }; if (do_section_details) @@ -3926,8 +3929,9 @@ get_elf_section_flags (bfd_vma sh_flags) default: index = -1; - if (elf_header.e_machine == EM_IA_64) + switch (elf_header.e_machine) { + case EM_IA_64: if (flag == SHF_IA_64_SHORT) index = 10; else if (flag == SHF_IA_64_NORECOV) @@ -3945,8 +3949,20 @@ get_elf_section_flags (bfd_vma sh_flags) default: break; } #endif + break; + + case EM_OLD_SPARCV9: + case EM_SPARC32PLUS: + case EM_SPARCV9: + case EM_SPARC: + if (flag == SHF_EXCLUDE) + index = 18; + else if (flag == SHF_ORDERED) + index = 19; + break; + default: + break; } - break; } if (index != -1) @@ -4327,6 +4343,8 @@ process_section_headers (FILE * file) if (is_32bit_elf) { + const char * link_too_big = NULL; + print_vma (section->sh_addr, LONG_HEX); printf ( " %6.6lx %6.6lx %2.2lx", @@ -4339,10 +4357,45 @@ process_section_headers (FILE * file) else printf (" %3s ", get_elf_section_flags (section->sh_flags)); - printf ("%2u %3u %2lu\n", - section->sh_link, - section->sh_info, - (unsigned long) section->sh_addralign); + if (section->sh_link >= elf_header.e_shnum) + { + link_too_big = ""; + /* The sh_link value is out of range. Normally this indicates + an error but it can have special values in SPARC binaries. */ + switch (elf_header.e_machine) + { + case EM_OLD_SPARCV9: + case EM_SPARC32PLUS: + case EM_SPARCV9: + case EM_SPARC: + if (section->sh_link == (SHN_BEFORE & 0xffff)) + link_too_big = "BEFORE"; + else if (section->sh_link == (SHN_AFTER & 0xffff)) + link_too_big = "AFTER"; + break; + default: + break; + } + } + + if (do_section_details) + { + if (link_too_big != NULL && * link_too_big) + printf ("<%s> ", link_too_big); + else + printf ("%2u ", section->sh_link); + printf ("%3u %2lu\n", section->sh_info, + (unsigned long) section->sh_addralign); + } + else + printf ("%2u %3u %2lu\n", + section->sh_link, + section->sh_info, + (unsigned long) section->sh_addralign); + + if (link_too_big && ! * link_too_big) + warn (_("section %u: sh_link value of %u is larger than the number of sections\n"), + i, section->sh_link); } else if (do_wide) { -- 2.30.2