This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Powerpc64 dynreloc miscount and aborts building shared lib
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sourceware dot org
- Date: Wed, 18 Jul 2007 20:56:15 +0930
- Subject: Powerpc64 dynreloc miscount and aborts building shared lib
This fixes an error in bfd_section_from_r_symndx, a function that is
supposed to find the section of a reloc symbol. It has a rather
curious interface in that if the reloc symbol has no real bfd section
(or if the reloc has no symbol), then it returns a default section
passed in as one of the input parameters. It also caches r_symndx
to section mapping. The problem with this is that a reloc with no
symbol causes the default section to be cached, which is wrong for a
following call with a different default section.
This can result in powerpc64 "dynreloc miscount" errors and aborts
(line 10985 of elf64-ppc.c) if the section size for dynamic relocs
isn't as expected.
* elf-bfd.h (struct sym_sec_cache): Delete "sec". Add "shndx".
* elf.c (bfd_section_from_r_symndx): Don't cache bfd section of
symbol. Instead cache ELF section index. Remove redundant
checks of st_shndx.
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.237
diff -u -p -r1.237 elf-bfd.h
--- bfd/elf-bfd.h 13 Jul 2007 10:44:12 -0000 1.237
+++ bfd/elf-bfd.h 18 Jul 2007 10:34:42 -0000
@@ -423,7 +423,7 @@ struct sym_sec_cache
{
bfd *abfd;
unsigned long indx[LOCAL_SYM_CACHE_SIZE];
- asection *sec[LOCAL_SYM_CACHE_SIZE];
+ unsigned int shndx[LOCAL_SYM_CACHE_SIZE];
};
/* Constant information held for an ELF backend. */
Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.398
diff -u -p -r1.398 elf.c
--- bfd/elf.c 13 Jul 2007 10:44:12 -0000 1.398
+++ bfd/elf.c 18 Jul 2007 11:03:08 -0000
@@ -2273,36 +2273,35 @@ bfd_section_from_r_symndx (bfd *abfd,
asection *sec,
unsigned long r_symndx)
{
- Elf_Internal_Shdr *symtab_hdr;
- unsigned char esym[sizeof (Elf64_External_Sym)];
- Elf_External_Sym_Shndx eshndx;
- Elf_Internal_Sym isym;
unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE;
+ asection *s;
- if (cache->abfd == abfd && cache->indx[ent] == r_symndx)
- return cache->sec[ent];
+ if (cache->abfd != abfd || cache->indx[ent] != r_symndx)
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+ unsigned char esym[sizeof (Elf64_External_Sym)];
+ Elf_External_Sym_Shndx eshndx;
+ Elf_Internal_Sym isym;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx,
- &isym, esym, &eshndx) == NULL)
- return NULL;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx,
+ &isym, esym, &eshndx) == NULL)
+ return NULL;
- if (cache->abfd != abfd)
- {
- memset (cache->indx, -1, sizeof (cache->indx));
- cache->abfd = abfd;
- }
- cache->indx[ent] = r_symndx;
- cache->sec[ent] = sec;
- if ((isym.st_shndx != SHN_UNDEF && isym.st_shndx < SHN_LORESERVE)
- || isym.st_shndx > SHN_HIRESERVE)
- {
- asection *s;
- s = bfd_section_from_elf_index (abfd, isym.st_shndx);
- if (s != NULL)
- cache->sec[ent] = s;
+ if (cache->abfd != abfd)
+ {
+ memset (cache->indx, -1, sizeof (cache->indx));
+ cache->abfd = abfd;
+ }
+ cache->indx[ent] = r_symndx;
+ cache->shndx[ent] = isym.st_shndx;
}
- return cache->sec[ent];
+
+ s = bfd_section_from_elf_index (abfd, cache->shndx[ent]);
+ if (s != NULL)
+ return s;
+
+ return sec;
}
/* Given an ELF section number, retrieve the corresponding BFD
--
Alan Modra
Australia Development Lab, IBM