From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 6864 invoked by alias); 2 Dec 2007 20:18:10 -0000 Received: (qmail 6855 invoked by uid 22791); 2 Dec 2007 20:18:08 -0000 X-Spam-Check-By: sourceware.org Received: from smtp.nildram.co.uk (HELO smtp.nildram.co.uk) (195.149.33.74) by sourceware.org (qpsmtpd/0.31) with ESMTP; Sun, 02 Dec 2007 20:18:02 +0000 Received: from firetop.home (85-211-136-23.dyn.gotadsl.co.uk [85.211.136.23]) by smtp.nildram.co.uk (Postfix) with ESMTP id E41FD4C196 for ; Sun, 2 Dec 2007 20:17:55 +0000 (GMT) Received: from richard by firetop.home with local (Exim 4.63) (envelope-from ) id 1IyvGI-0007BQ-Iu for binutils@sourceware.org; Sun, 02 Dec 2007 20:17:58 +0000 From: Richard Sandiford To: binutils@sourceware.org Mail-Followup-To: binutils@sourceware.org, rsandifo@nildram.co.uk Subject: [PATCH 1/7] Fix --gc-sections for C++ MIPS ELF References: <87r6i4svjg.fsf@firetop.home> Date: Sun, 02 Dec 2007 20:18:00 -0000 In-Reply-To: <87r6i4svjg.fsf@firetop.home> (Richard Sandiford's message of "Sun\, 02 Dec 2007 20\:15\:15 +0000") Message-ID: <87mysssvex.fsf@firetop.home> User-Agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org X-SW-Source: 2007-12/txt/msg00001.txt.bz2 The discard routines store some relocation information in a structure called elf_reloc_cookie, which the .eh_frame parser uses to check that the relocs are as expected. If we're going to parse .eh_frame earlier, it would be good to have cookies at that stage too. _bfd_elf_gc_mark uses the same information that you get from an elf_reloc_cookie, but stores it in separate variables. This first patch therefore splits out the cookie initialisation and finalisation routines from bfd_elf_discard_info and uses them in _bfd_elf_gc_mark as well. The patch also splits out parts of _bfd_elf_gc_mark so that they can be reused in later patches. The patch fixes a potential memory leak, although it probably never occured in practice. _bfd_elf_gc_mark behaves as though it could be the first routine to set symtab_hdr->contents: if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym) { if (! info->keep_memory) free (isym); else symtab_hdr->contents = (unsigned char *) isym; } but it does this after a loop that involves recursive calls to _bfd_elf_gc_mark. If one of those recursive calls was for the same input bfd, that call would still see a null contents field, and would therefore create a second copy of the memory. I avoided this by putting the symtab_hdr->contents assignment in the initialisation code instead. Richard bfd/ * elf-bfd.h (_bfd_elf_gc_mark_rsec, _bfd_elf_gc_mark_reloc): Declare. (_bfd_elf_gc_mark): Use elf_gc_mark_hook_fn. * elflink.c (init_reloc_cookie, fini_reloc_cookie) (init_reloc_cookie_rels, fini_reloc_cookie_rels): New functions, split out from... (bfd_elf_discard_info): ...here. (init_reloc_cookie_for_section): New function. (fini_reloc_cookie_for_section): Likewise. (_bfd_elf_gc_mark_rsec, _bfd_elf_gc_mark_reloc): New functions, split out from... (_bfd_elf_gc_mark): ...here. Use init_reloc_cookie_for_section and fini_reloc_cookie_for_section. Index: bfd/elf-bfd.h =================================================================== *** bfd/elf-bfd.h 2007-12-02 16:59:44.000000000 +0000 --- bfd/elf-bfd.h 2007-12-02 16:59:46.000000000 +0000 *************** extern void _bfd_elf_set_osabi (bfd * , *** 1971,1980 **** (asection *, struct bfd_link_info *, Elf_Internal_Rela *, struct elf_link_hash_entry *, Elf_Internal_Sym *); extern bfd_boolean _bfd_elf_gc_mark ! (struct bfd_link_info *, asection *, ! asection * (*) (asection *, struct bfd_link_info *, Elf_Internal_Rela *, ! struct elf_link_hash_entry *, Elf_Internal_Sym *)); extern bfd_boolean bfd_elf_gc_common_finalize_got_offsets (bfd *, struct bfd_link_info *); --- 1971,1986 ---- (asection *, struct bfd_link_info *, Elf_Internal_Rela *, struct elf_link_hash_entry *, Elf_Internal_Sym *); + extern asection *_bfd_elf_gc_mark_rsec + (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn, + struct elf_reloc_cookie *); + + extern bfd_boolean _bfd_elf_gc_mark_reloc + (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn, + struct elf_reloc_cookie *, bfd_boolean); + extern bfd_boolean _bfd_elf_gc_mark ! (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn); extern bfd_boolean bfd_elf_gc_common_finalize_got_offsets (bfd *, struct bfd_link_info *); Index: bfd/elflink.c =================================================================== *** bfd/elflink.c 2007-12-02 16:59:44.000000000 +0000 --- bfd/elflink.c 2007-12-02 17:01:03.000000000 +0000 *************** bfd_elf_final_link (bfd *abfd, struct bf *** 10940,10945 **** --- 10940,11078 ---- return FALSE; } + /* Initialize COOKIE for input bfd ABFD. */ + + static bfd_boolean + init_reloc_cookie (struct elf_reloc_cookie *cookie, + struct bfd_link_info *info, bfd *abfd) + { + Elf_Internal_Shdr *symtab_hdr; + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (abfd); + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + cookie->abfd = abfd; + cookie->sym_hashes = elf_sym_hashes (abfd); + cookie->bad_symtab = elf_bad_symtab (abfd); + if (cookie->bad_symtab) + { + cookie->locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym; + cookie->extsymoff = 0; + } + else + { + cookie->locsymcount = symtab_hdr->sh_info; + cookie->extsymoff = symtab_hdr->sh_info; + } + + if (bed->s->arch_size == 32) + cookie->r_sym_shift = 8; + else + cookie->r_sym_shift = 32; + + cookie->locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; + if (cookie->locsyms == NULL && cookie->locsymcount != 0) + { + cookie->locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr, + cookie->locsymcount, 0, + NULL, NULL, NULL); + if (cookie->locsyms == NULL) + { + info->callbacks->einfo (_("%P%X: can not read symbols: %E\n")); + return FALSE; + } + if (info->keep_memory) + symtab_hdr->contents = (bfd_byte *) cookie->locsyms; + } + return TRUE; + } + + /* Free the memory allocated by init_reloc_cookie, if appropriate. */ + + static void + fini_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd) + { + Elf_Internal_Shdr *symtab_hdr; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + if (cookie->locsyms != NULL + && symtab_hdr->contents != (unsigned char *) cookie->locsyms) + free (cookie->locsyms); + } + + /* Initialize the relocation information in COOKIE for input section SEC + of input bfd ABFD. */ + + static bfd_boolean + init_reloc_cookie_rels (struct elf_reloc_cookie *cookie, + struct bfd_link_info *info, bfd *abfd, + asection *sec) + { + const struct elf_backend_data *bed; + + if (sec->reloc_count == 0) + { + cookie->rels = NULL; + cookie->relend = NULL; + } + else + { + bed = get_elf_backend_data (abfd); + + cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, + info->keep_memory); + if (cookie->rels == NULL) + return FALSE; + cookie->rel = cookie->rels; + cookie->relend = (cookie->rels + + sec->reloc_count * bed->s->int_rels_per_ext_rel); + } + cookie->rel = cookie->rels; + return TRUE; + } + + /* Free the memory allocated by init_reloc_cookie_rels, + if appropriate. */ + + static void + fini_reloc_cookie_rels (struct elf_reloc_cookie *cookie, + asection *sec) + { + if (cookie->rels && elf_section_data (sec)->relocs != cookie->rels) + free (cookie->rels); + } + + /* Initialize the whole of COOKIE for input section SEC. */ + + static bfd_boolean + init_reloc_cookie_for_section (struct elf_reloc_cookie *cookie, + struct bfd_link_info *info, + asection *sec) + { + if (!init_reloc_cookie (cookie, info, sec->owner)) + goto error1; + if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec)) + goto error2; + return TRUE; + + error2: + fini_reloc_cookie (cookie, sec->owner); + error1: + return FALSE; + } + + /* Free the memory allocated by init_reloc_cookie_for_section, + if appropriate. */ + + static void + fini_reloc_cookie_for_section (struct elf_reloc_cookie *cookie, + asection *sec) + { + fini_reloc_cookie_rels (cookie, sec); + fini_reloc_cookie (cookie, sec->owner); + } + /* Garbage collect unused sections. */ /* Default gc_mark_hook. */ *************** _bfd_elf_gc_mark_hook (asection *sec, *** 10972,10977 **** --- 11105,11167 ---- return NULL; } + /* COOKIE->rel describes a relocation against section SEC, which is + a section we've decided to keep. Return the section that contains + the relocation symbol, or NULL if no section contains it. */ + + asection * + _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec, + elf_gc_mark_hook_fn gc_mark_hook, + struct elf_reloc_cookie *cookie) + { + unsigned long r_symndx; + struct elf_link_hash_entry *h; + + r_symndx = cookie->rel->r_info >> cookie->r_sym_shift; + if (r_symndx == 0) + return NULL; + + if (r_symndx >= cookie->locsymcount + || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) + { + h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); + } + + return (*gc_mark_hook) (sec, info, cookie->rel, NULL, + &cookie->locsyms[r_symndx]); + } + + /* COOKIE->rel describes a relocation against section SEC, which is + a section we've decided to keep. Mark the section that contains + the relocation symbol. IS_EH is true if the mark comes from + .eh_frame. */ + + bfd_boolean + _bfd_elf_gc_mark_reloc (struct bfd_link_info *info, + asection *sec, + elf_gc_mark_hook_fn gc_mark_hook, + struct elf_reloc_cookie *cookie, + bfd_boolean is_eh) + { + asection *rsec; + + rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie); + if (rsec && !rsec->gc_mark) + { + if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour) + rsec->gc_mark = 1; + else if (is_eh) + rsec->gc_mark_from_eh = 1; + else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook)) + return FALSE; + } + return TRUE; + } + /* The mark phase of garbage collection. For a given section, mark it and any sections in this section's group, and all the sections which define symbols to which it refers. */ *************** _bfd_elf_gc_mark (struct bfd_link_info * *** 10998,11100 **** is_eh = strcmp (sec->name, ".eh_frame") == 0; if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0) { ! Elf_Internal_Rela *relstart, *rel, *relend; ! Elf_Internal_Shdr *symtab_hdr; ! struct elf_link_hash_entry **sym_hashes; ! size_t nlocsyms; ! size_t extsymoff; ! bfd *input_bfd = sec->owner; ! const struct elf_backend_data *bed = get_elf_backend_data (input_bfd); ! Elf_Internal_Sym *isym = NULL; ! int r_sym_shift; ! symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; ! sym_hashes = elf_sym_hashes (input_bfd); ! ! /* Read the local symbols. */ ! if (elf_bad_symtab (input_bfd)) ! { ! nlocsyms = symtab_hdr->sh_size / bed->s->sizeof_sym; ! extsymoff = 0; ! } else - extsymoff = nlocsyms = symtab_hdr->sh_info; - - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isym == NULL && nlocsyms != 0) - { - isym = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, nlocsyms, 0, - NULL, NULL, NULL); - if (isym == NULL) - return FALSE; - } - - /* Read the relocations. */ - relstart = _bfd_elf_link_read_relocs (input_bfd, sec, NULL, NULL, - info->keep_memory); - if (relstart == NULL) - { - ret = FALSE; - goto out1; - } - relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel; - - if (bed->s->arch_size == 32) - r_sym_shift = 8; - else - r_sym_shift = 32; - - for (rel = relstart; rel < relend; rel++) - { - unsigned long r_symndx; - asection *rsec; - struct elf_link_hash_entry *h; - - r_symndx = rel->r_info >> r_sym_shift; - if (r_symndx == 0) - continue; - - if (r_symndx >= nlocsyms - || ELF_ST_BIND (isym[r_symndx].st_info) != STB_LOCAL) - { - h = sym_hashes[r_symndx - extsymoff]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - rsec = (*gc_mark_hook) (sec, info, rel, h, NULL); - } - else - { - rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]); - } - - if (rsec && !rsec->gc_mark) - { - if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour) - rsec->gc_mark = 1; - else if (is_eh) - rsec->gc_mark_from_eh = 1; - else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook)) - { - ret = FALSE; - goto out2; - } - } - } - - out2: - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - out1: - if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym) { ! if (! info->keep_memory) ! free (isym); ! else ! symtab_hdr->contents = (unsigned char *) isym; } } - return ret; } --- 11188,11209 ---- is_eh = strcmp (sec->name, ".eh_frame") == 0; if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0) { ! struct elf_reloc_cookie cookie; ! if (!init_reloc_cookie_for_section (&cookie, info, sec)) ! ret = FALSE; else { ! for (; cookie.rel < cookie.relend; cookie.rel++) ! if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, ! &cookie, is_eh)) ! { ! ret = FALSE; ! break; ! } ! fini_reloc_cookie_for_section (&cookie, sec); } } return ret; } *************** bfd_elf_discard_info (bfd *output_bfd, s *** 11777,11786 **** { struct elf_reloc_cookie cookie; asection *stab, *eh; - Elf_Internal_Shdr *symtab_hdr; const struct elf_backend_data *bed; bfd *abfd; - unsigned int count; bfd_boolean ret = FALSE; if (info->traditional_format --- 11886,11893 ---- *************** bfd_elf_discard_info (bfd *output_bfd, s *** 11819,11913 **** && bed->elf_backend_discard_info == NULL) continue; ! symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ! cookie.abfd = abfd; ! cookie.sym_hashes = elf_sym_hashes (abfd); ! cookie.bad_symtab = elf_bad_symtab (abfd); ! if (cookie.bad_symtab) ! { ! cookie.locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym; ! cookie.extsymoff = 0; ! } ! else ! { ! cookie.locsymcount = symtab_hdr->sh_info; ! cookie.extsymoff = symtab_hdr->sh_info; ! } ! ! if (bed->s->arch_size == 32) ! cookie.r_sym_shift = 8; ! else ! cookie.r_sym_shift = 32; ! ! cookie.locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; ! if (cookie.locsyms == NULL && cookie.locsymcount != 0) ! { ! cookie.locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr, ! cookie.locsymcount, 0, ! NULL, NULL, NULL); ! if (cookie.locsyms == NULL) ! { ! info->callbacks->einfo (_("%P%X: can not read symbols: %E\n")); ! return FALSE; ! } ! } ! if (stab != NULL) { ! cookie.rels = NULL; ! count = stab->reloc_count; ! if (count != 0) ! cookie.rels = _bfd_elf_link_read_relocs (abfd, stab, NULL, NULL, ! info->keep_memory); ! if (cookie.rels != NULL) ! { ! cookie.rel = cookie.rels; ! cookie.relend = cookie.rels; ! cookie.relend += count * bed->s->int_rels_per_ext_rel; ! if (_bfd_discard_section_stabs (abfd, stab, ! elf_section_data (stab)->sec_info, ! bfd_elf_reloc_symbol_deleted_p, ! &cookie)) ! ret = TRUE; ! if (elf_section_data (stab)->relocs != cookie.rels) ! free (cookie.rels); ! } } ! if (eh != NULL) { - cookie.rels = NULL; - count = eh->reloc_count; - if (count != 0) - cookie.rels = _bfd_elf_link_read_relocs (abfd, eh, NULL, NULL, - info->keep_memory); - cookie.rel = cookie.rels; - cookie.relend = cookie.rels; - if (cookie.rels != NULL) - cookie.relend += count * bed->s->int_rels_per_ext_rel; - if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, bfd_elf_reloc_symbol_deleted_p, &cookie)) ret = TRUE; ! ! if (cookie.rels != NULL ! && elf_section_data (eh)->relocs != cookie.rels) ! free (cookie.rels); } if (bed->elf_backend_discard_info != NULL && (*bed->elf_backend_discard_info) (abfd, &cookie, info)) ret = TRUE; ! if (cookie.locsyms != NULL ! && symtab_hdr->contents != (unsigned char *) cookie.locsyms) ! { ! if (! info->keep_memory) ! free (cookie.locsyms); ! else ! symtab_hdr->contents = (unsigned char *) cookie.locsyms; ! } } if (info->eh_frame_hdr --- 11926,11961 ---- && bed->elf_backend_discard_info == NULL) continue; ! if (!init_reloc_cookie (&cookie, info, abfd)) ! return FALSE; ! if (stab != NULL ! && stab->reloc_count > 0 ! && init_reloc_cookie_rels (&cookie, info, abfd, stab)) { ! if (_bfd_discard_section_stabs (abfd, stab, ! elf_section_data (stab)->sec_info, ! bfd_elf_reloc_symbol_deleted_p, ! &cookie)) ! ret = TRUE; ! fini_reloc_cookie_rels (&cookie, stab); } ! if (eh != NULL ! && init_reloc_cookie_rels (&cookie, info, abfd, eh)) { if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, bfd_elf_reloc_symbol_deleted_p, &cookie)) ret = TRUE; ! fini_reloc_cookie_rels (&cookie, eh); } if (bed->elf_backend_discard_info != NULL && (*bed->elf_backend_discard_info) (abfd, &cookie, info)) ret = TRUE; ! fini_reloc_cookie (&cookie, abfd); } if (info->eh_frame_hdr