binutils/ 2004-04-26 H.J. Lu * readelf.c (do_section_groups): New. (options): Add --section-groups/-g. (usage): Mention --section-groups/-g. (parse_args): Support --section-groups/-g. (get_group_flags): New. (process_section_groups): New. (process_object): Call process_section_groups. gas/ 2004-04-26 H.J. Lu * config/obj-elf.c (obj_elf_change_section): Check if the old group name is NULL before comparison. gas/testsuite/ 2004-04-26 H.J. Lu * gas/elf/elf.exp: Add group0a, group0b and group1 for section group. * gas/elf/group0.s: New file. * gas/elf/group0a.d: Likewise. * gas/elf/group0b.d: Likewise. * gas/elf/group1.e: Likewise. * gas/elf/group1.s: Likewise. --- binutils/binutils/readelf.c.group 2004-04-01 08:34:45.000000000 -0800 +++ binutils/binutils/readelf.c 2004-04-26 14:55:53.000000000 -0700 @@ -140,6 +140,7 @@ int do_dynamic; int do_syms; int do_reloc; int do_sections; +int do_section_groups; int do_segments; int do_unwind; int do_using_dynamic; @@ -2393,6 +2394,7 @@ struct option options[] = {"segments", no_argument, 0, 'l'}, {"sections", no_argument, 0, 'S'}, {"section-headers", no_argument, 0, 'S'}, + {"section-groups", no_argument, 0, 'g'}, {"symbols", no_argument, 0, 's'}, {"syms", no_argument, 0, 's'}, {"relocs", no_argument, 0, 'r'}, @@ -2426,6 +2428,7 @@ usage (void) --segments An alias for --program-headers\n\ -S --section-headers Display the sections' header\n\ --sections An alias for --section-headers\n\ + -g --section-groups Display the section groups\n\ -e --headers Equivalent to: -h -l -S\n\ -s --syms Display the symbol table\n\ --symbols An alias for --syms\n\ @@ -2493,7 +2496,7 @@ parse_args (int argc, char **argv) usage (); while ((c = getopt_long - (argc, argv, "ersuahnldSDAIw::x:i:vVWH", options, NULL)) != EOF) + (argc, argv, "ersuahnldSDAIgw::x:i:vVWH", options, NULL)) != EOF) { char *cp; int section; @@ -2514,12 +2517,16 @@ parse_args (int argc, char **argv) do_dynamic++; do_header++; do_sections++; + do_section_groups++; do_segments++; do_version++; do_histogram++; do_arch++; do_notes++; break; + case 'g': + do_section_groups++; + break; case 'e': do_header++; do_sections++; @@ -2746,7 +2753,8 @@ parse_args (int argc, char **argv) if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections && !do_segments && !do_header && !do_dump && !do_version - && !do_histogram && !do_debugging && !do_arch && !do_notes) + && !do_histogram && !do_debugging && !do_arch && !do_notes + && !do_section_groups) usage (); else if (argc < 3) { @@ -3703,6 +3711,124 @@ process_section_headers (FILE *file) return 1; } +static const char * +get_group_flags (unsigned int flags) +{ + static char buff[32]; + switch (flags) + { + case GRP_COMDAT: + return "COMDAT"; + + default: + sprintf (buff, _("[: 0x%x]"), flags); + break; + } + return buff; +} + +static int +process_section_groups (FILE *file) +{ + Elf_Internal_Shdr *section; + unsigned int i; + + if (!do_section_groups) + return 1; + + if (elf_header.e_shnum == 0) + { + if (do_section_groups) + printf (_("\nThere are no section groups in this file.\n")); + + return 1; + } + + if (section_headers == NULL) + { + error (_("Section headers are not available!\n")); + abort (); + } + + /* Scan the sections for the group section. */ + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + { + if (section->sh_type == SHT_GROUP) + { + char *name = SECTION_NAME (section); + char *group_name, *strtab, *start, *indices; + unsigned int entry, j, size; + Elf_Internal_Sym *sym; + Elf_Internal_Shdr *symtab_sec, *strtab_sec, *sec; + Elf_Internal_Sym *symtab; + + /* Get the symbol table. */ + symtab_sec = SECTION_HEADER (section->sh_link); + if (symtab_sec->sh_type != SHT_SYMTAB) + { + error (_("Bad sh_link in group section `%s'\n"), name); + continue; + } + symtab = GET_ELF_SYMBOLS (file, symtab_sec); + + sym = symtab + section->sh_info; + + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + bfd_vma sec_index = SECTION_HEADER_INDEX (sym->st_shndx); + if (sec_index == 0) + { + error (_("Bad sh_info in group section `%s'\n"), name); + continue; + } + + group_name = SECTION_NAME (section_headers + sec_index); + strtab = NULL; + } + else + { + /* Get the string table. */ + strtab_sec = SECTION_HEADER (symtab_sec->sh_link); + strtab = get_data (NULL, file, strtab_sec->sh_offset, + strtab_sec->sh_size, + _("string table")); + + group_name = strtab + sym->st_name; + } + + start = get_data (NULL, file, section->sh_offset, + section->sh_size, _("section data")); + + indices = start; + size = (section->sh_size / section->sh_entsize) - 1; + entry = byte_get (indices, 4); + indices += 4; + printf ("\n%s group section `%s' [%s] contains %u sections:\n", + get_group_flags (entry), name, group_name, size); + + printf (_(" [Index] Name\n")); + for (j = 0; j < size; j++) + { + entry = byte_get (indices, 4); + indices += 4; + + sec = SECTION_HEADER (entry); + printf (" [%5u] %s\n", + entry, SECTION_NAME (sec)); + } + + if (strtab) + free (strtab); + if (start) + free (start); + } + } + + return 1; +} + struct { const char *name; @@ -10331,6 +10457,8 @@ process_object (char *file_name, FILE *f process_section_contents (file); + process_section_groups (file); + process_corefile_contents (file); process_gnu_liblist (file); --- binutils/gas/config/obj-elf.c.group 2004-03-18 10:11:27.000000000 -0800 +++ binutils/gas/config/obj-elf.c 2004-04-26 14:41:52.000000000 -0700 @@ -645,7 +645,8 @@ obj_elf_change_section (const char *name if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize) as_warn (_("ignoring changed section entity size for %s"), name); if ((attr & SHF_GROUP) != 0 - && strcmp (elf_group_name (old_sec), group_name) != 0) + && (elf_group_name (old_sec) == NULL + || strcmp (elf_group_name (old_sec), group_name) != 0)) as_warn (_("ignoring new section group for %s"), name); } --- binutils/gas/testsuite/gas/elf/elf.exp.group 2003-11-10 11:36:12.000000000 -0800 +++ binutils/gas/testsuite/gas/elf/elf.exp 2004-04-26 14:21:00.000000000 -0700 @@ -48,6 +48,9 @@ if { ([istarget "*-*-elf*"] set target_machine -m32r } run_dump_test "ehopt0" + run_dump_test "group0a" + run_dump_test "group0b" + run_list_test "group1" "" "" "" run_dump_test "section0" run_dump_test "section1" run_list_test "section2" "$target_machine" "-al" "" --- binutils/gas/testsuite/gas/elf/group0.s.group 2004-04-26 11:03:08.000000000 -0700 +++ binutils/gas/testsuite/gas/elf/group0.s 2004-04-26 10:45:11.000000000 -0700 @@ -0,0 +1,4 @@ + .section .foo,"axG",@progbits,.foo_group,comdat + .byte 1 + .section .bar,"aG",@progbits,.foo_group,comdat + .byte 1 --- binutils/gas/testsuite/gas/elf/group0a.d.group 2004-04-26 11:03:05.000000000 -0700 +++ binutils/gas/testsuite/gas/elf/group0a.d 2004-04-26 14:29:47.000000000 -0700 @@ -0,0 +1,9 @@ +#readelf: -SW +#name: group section +#source: group0.s + +#... +[ ]*\[.*\][ ]+\.foo[ ]+PROGBITS.*[ ]+AXG[ ]+.* +[ ]*\[.*\][ ]+\.bar[ ]+PROGBITS.*[ ]+AG[ ]+.* +[ ]*\[.*\][ ]+\.foo_group[ ]+GROUP.* +#pass --- binutils/gas/testsuite/gas/elf/group0b.d.group 2004-04-26 14:21:14.000000000 -0700 +++ binutils/gas/testsuite/gas/elf/group0b.d 2004-04-26 14:22:30.000000000 -0700 @@ -0,0 +1,10 @@ +#readelf: -g +#name: group section +#source: group0.s + +#... +COMDAT group section `.foo_group' \[.foo_group\] contains 2 sections: +[ ]+\[Index\][ ]+Name +[ ]+\[.*\][ ]+.foo +[ ]+\[.*\][ ]+.bar +#pass --- binutils/gas/testsuite/gas/elf/group1.e.group 2004-04-26 11:03:19.000000000 -0700 +++ binutils/gas/testsuite/gas/elf/group1.e 2004-04-26 11:02:40.000000000 -0700 @@ -0,0 +1,7 @@ + +Symbol table '.symtab' contains 4 entries: + Num: Value[ ]* Size Type Bind Vis Ndx Name + 0: 0+0 0 NOTYPE LOCAL DEFAULT UND + 1: 0+0 0 SECTION LOCAL DEFAULT 1 + 2: 0+0 0 SECTION LOCAL DEFAULT 2 + 3: 0+0 0 SECTION LOCAL DEFAULT 3 --- binutils/gas/testsuite/gas/elf/group1.s.group 2004-04-26 11:03:11.000000000 -0700 +++ binutils/gas/testsuite/gas/elf/group1.s 2004-04-26 10:45:57.000000000 -0700 @@ -0,0 +1,2 @@ + .section .text,"axG",@progbits,.foo_group,comdat + .byte 1