From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3680 invoked by alias); 1 Jun 2009 05:06:02 -0000 Received: (qmail 3665 invoked by uid 22791); 1 Jun 2009 05:06:00 -0000 X-SWARE-Spam-Status: No, hits=1.2 required=5.0 tests=AWL,BAYES_00,NO_DNS_FOR_FROM,TVD_STOCK1 X-Spam-Check-By: sourceware.org Received: from mga09.intel.com (HELO mga09.intel.com) (134.134.136.24) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 01 Jun 2009 05:05:53 +0000 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga102.jf.intel.com with ESMTP; 31 May 2009 21:54:55 -0700 X-ExtLoop1: 1 Received: from gnu-6.sc.intel.com ([10.3.194.111]) by orsmga002.jf.intel.com with ESMTP; 31 May 2009 22:13:14 -0700 Received: by gnu-6.sc.intel.com (Postfix, from userid 500) id 1CD993B57B1; Sun, 31 May 2009 22:05:44 -0700 (PDT) Date: Mon, 01 Jun 2009 05:06:00 -0000 From: "H.J. Lu" To: binutils@sources.redhat.com Cc: nickc@redhat.com Subject: PATCH: Generic STT_GNU_IFUNC patch Message-ID: <20090601050543.GA27034@lucon.org> Reply-To: "H.J. Lu" MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.18 (2008-05-17) 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: 2009-06/txt/msg00001.txt.bz2 Here is the generic STT_GNU_IFUNC patch. I need it to complete STT_GNU_IFUNC support on Linux/ia32 and Linux/Intel64. I will fix Linux/ia32 and Linux/Intel64 with a followup patch. Nick, can you take a look? Thanks. H.J. ---- bfd/ 2009-05-31 H.J. Lu * elf-bfd.h (struct bfd_elf_section_data): Remove indirect_relocs. (_bfd_elf_make_ifunc_reloc_section): Removed. (_bfd_elf_is_ifunc_symbol): Likewise. (_bfd_elf_create_static_ifunc_sections): New. * elflink.c (_bfd_elf_adjust_dynamic_symbol): Move STT_GNU_IFUNC symbol check to ... (elf_link_add_object_symbols): Here. (_bfd_elf_link_hash_hide_symbol): Don't clean plt on STT_GNU_IFUNC symbol. (elf_link_output_extsym): Call elf_backend_finish_dynamic_symbol if a STT_GNU_IFUNC symbol is referenced in a non-shared object. (IFUNC_INFIX): Removed. (get_ifunc_reloc_section_name): Likewise. (_bfd_elf_make_ifunc_reloc_section): Likewise. (_bfd_elf_is_ifunc_symbol): Likewise. (_bfd_elf_create_static_ifunc_sections): New. ld/ 2009-05-31 H.J. Lu * scripttempl/elf.sc (PLT): Add "*(.iplt)". (GOT): Add "*(.igot.plt)a" and "*(.igot)". (GOTPLT): Add "*(.igot)". (__rel_iplt_start): New. (__rel_iplt_end): Likewise. (__rela_iplt_start): Likewise. (__rela_iplt_end): Likewise. diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elf-bfd.h binutils/bfd/elf-bfd.h --- ../binutils/src/bfd/elf-bfd.h 2009-05-26 15:19:00.000000000 -0700 +++ binutils/bfd/elf-bfd.h 2009-05-30 09:38:42.000000000 -0700 @@ -1299,9 +1299,6 @@ struct bfd_elf_section_data /* A pointer to the bfd section used for dynamic relocs. */ asection *sreloc; - /* A pointer to the bfd section used for dynamic relocs against ifunc symbols. */ - asection *indirect_relocs; - union { /* Group name, if this section is a member of a group. */ const char *name; @@ -2149,15 +2146,12 @@ extern int _bfd_elf_obj_attrs_arg_type ( extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *); extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *); -extern asection * _bfd_elf_make_ifunc_reloc_section - (bfd *, asection *, bfd *, unsigned int); +extern bfd_boolean _bfd_elf_create_static_ifunc_sections + (bfd *, struct bfd_link_info *); /* Large common section. */ extern asection _bfd_elf_large_com_section; -extern bfd_boolean _bfd_elf_is_ifunc_symbol - (bfd *, struct elf_link_hash_entry *); - /* This is the condition under which finish_dynamic_symbol will be called. If our finish_dynamic_symbol isn't called, we'll need to do something about initializing any .plt and .got entries in relocate_section. */ diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/bfd/elflink.c binutils/bfd/elflink.c --- ../binutils/src/bfd/elflink.c 2009-05-26 15:19:00.000000000 -0700 +++ binutils/bfd/elflink.c 2009-05-31 12:01:00.000000000 -0700 @@ -2675,13 +2675,6 @@ _bfd_elf_adjust_dynamic_symbol (struct e dynobj = elf_hash_table (eif->info)->dynobj; bed = get_elf_backend_data (dynobj); - - if (h->type == STT_GNU_IFUNC - && (bed->elf_osabi == ELFOSABI_LINUX - /* GNU/Linux is still using the default value 0. */ - || bed->elf_osabi == ELFOSABI_NONE)) - h->needs_plt = 1; - if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h)) { eif->failed = TRUE; @@ -4294,6 +4287,10 @@ elf_link_add_object_symbols (bfd *abfd, h->type = ELF_ST_TYPE (isym->st_info); } + + /* STT_GNU_IFUNC symbol must go through PLT. */ + if (h->type == STT_GNU_IFUNC) + h->needs_plt = 1; /* Merge st_other field. */ elf_merge_st_other (abfd, h, isym, definition, dynamic); @@ -6669,8 +6666,12 @@ _bfd_elf_link_hash_hide_symbol (struct b struct elf_link_hash_entry *h, bfd_boolean force_local) { - h->plt = elf_hash_table (info)->init_plt_offset; - h->needs_plt = 0; + /* STT_GNU_IFUNC symbol must go through PLT. */ + if (h->type != STT_GNU_IFUNC) + { + h->plt = elf_hash_table (info)->init_plt_offset; + h->needs_plt = 0; + } if (force_local) { h->forced_local = 1; @@ -8649,14 +8650,18 @@ elf_link_output_extsym (struct elf_link_ /* Give the processor backend a chance to tweak the symbol value, and also to finish up anything that needs to be done for this symbol. FIXME: Not calling elf_backend_finish_dynamic_symbol for - forced local syms when non-shared is due to a historical quirk. */ - if ((h->dynindx != -1 - || h->forced_local) - && ((finfo->info->shared - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - || !h->forced_local) - && elf_hash_table (finfo->info)->dynamic_sections_created) + forced local syms when non-shared is due to a historical quirk. + STT_GNU_IFUNC symbol must go through PLT. */ + if ((h->type == STT_GNU_IFUNC + && h->ref_regular + && !finfo->info->relocatable) + || ((h->dynindx != -1 + || h->forced_local) + && ((finfo->info->shared + && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + || !h->forced_local) + && elf_hash_table (finfo->info)->dynamic_sections_created)) { if (! ((*bed->elf_backend_finish_dynamic_symbol) (finfo->output_bfd, finfo->info, h, &sym))) @@ -12487,88 +12492,87 @@ _bfd_elf_make_dynamic_reloc_section (ase return reloc_sec; } -/* Returns the name of the ifunc using dynamic reloc section associated with SEC. */ -#define IFUNC_INFIX ".ifunc" +/* Create sections needed by STT_GNU_IFUNC symbol for static + executables. */ -static const char * -get_ifunc_reloc_section_name (bfd * abfd, - asection * sec) +bfd_boolean +_bfd_elf_create_static_ifunc_sections (bfd *abfd, + struct bfd_link_info *info) { - const char * dot; - char * name; - const char * base_name; - unsigned int strndx = elf_elfheader (abfd)->e_shstrndx; - unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name; - - base_name = bfd_elf_string_from_elf_section (abfd, strndx, shnam); - if (base_name == NULL) - return NULL; + flagword flags, pltflags; + int ptralign; + asection *s; + const struct elf_backend_data *bed; - dot = strchr (base_name + 1, '.'); - name = bfd_alloc (abfd, strlen (base_name) + strlen (IFUNC_INFIX) + 1); - sprintf (name, "%.*s%s%s", (int)(dot - base_name), base_name, IFUNC_INFIX, dot); + /* Should never be called for shared library. */ + BFD_ASSERT (!info->shared); - return name; -} - -/* Like _bfd_elf_make_dynamic_reloc_section but it creates a - section for holding relocs against symbols with the STT_GNU_IFUNC - type. The section is attached to the OWNER bfd but it is created - with a name based on SEC from ABFD. */ + /* This function may be called more than once. */ + s = bfd_get_section_by_name (abfd, ".iplt"); + if (s != NULL) + return TRUE; -asection * -_bfd_elf_make_ifunc_reloc_section (bfd * abfd, - asection * sec, - bfd * owner, - unsigned int align) -{ - asection * reloc_sec = elf_section_data (sec)->indirect_relocs; + bed = get_elf_backend_data (abfd); - if (reloc_sec == NULL) - { - const char * name = get_ifunc_reloc_section_name (abfd, sec); + /* We need to create .iplt, .rel[a].iplt, .igot, .igot.plt, */ + flags = bed->dynamic_sec_flags; - if (name == NULL) - return NULL; + pltflags = flags; + if (bed->plt_not_loaded) + /* We do not clear SEC_ALLOC here because we still want the OS to + allocate space for the section; it's just that there's nothing + to read in from the object file. */ + pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS); + else + pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD; + if (bed->plt_readonly) + pltflags |= SEC_READONLY; - reloc_sec = bfd_get_section_by_name (owner, name); + s = bfd_make_section_with_flags (abfd, ".iplt", pltflags); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) + return FALSE; - if (reloc_sec == NULL) - { - flagword flags; + s = bfd_make_section_with_flags (abfd, + (bed->rela_plts_and_copies_p + ? ".rela.iplt" : ".rel.iplt"), + flags | SEC_READONLY); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) + return FALSE; - flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED); - if ((sec->flags & SEC_ALLOC) != 0) - flags |= SEC_ALLOC | SEC_LOAD; + switch (bed->s->arch_size) + { + case 32: + ptralign = 2; + break; - reloc_sec = bfd_make_section_with_flags (owner, name, flags); - - if (reloc_sec != NULL - && ! bfd_set_section_alignment (owner, reloc_sec, align)) - reloc_sec = NULL; - } + case 64: + ptralign = 3; + break; - elf_section_data (sec)->indirect_relocs = reloc_sec; + default: + bfd_set_error (bfd_error_bad_value); + return FALSE; } - return reloc_sec; -} - -/* Returns true if the hash entry refers to a symbol marked for - indirect handling during reloc processing. */ - -bfd_boolean -_bfd_elf_is_ifunc_symbol (bfd *abfd, struct elf_link_hash_entry *h) -{ - const struct elf_backend_data * bed; - - if (abfd == NULL || h == NULL) - return FALSE; + /* We don't need the .igot section if we have the .igot.plt + section. */ - bed = get_elf_backend_data (abfd); + if (bed->want_got_plt) + { + s = bfd_make_section_with_flags (abfd, ".igot.plt", flags); + if (s == NULL + || !bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + } + else + { + s = bfd_make_section_with_flags (abfd, ".igot", flags); + if (s == NULL + || !bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + } - /* GNU/Linux is still using the default value ELFOSABI_NONE. */ - return (h->type == STT_GNU_IFUNC - && (bed->elf_osabi == ELFOSABI_LINUX - || bed->elf_osabi == ELFOSABI_NONE)); + return TRUE; } diff -x REVISION -x .svn -x CVS -uprN -x ChangeLog.ifunc ../binutils/src/ld/scripttempl/elf.sc binutils/ld/scripttempl/elf.sc --- ../binutils/src/ld/scripttempl/elf.sc 2009-05-05 10:55:58.000000000 -0700 +++ binutils/ld/scripttempl/elf.sc 2009-05-31 20:28:01.000000000 -0700 @@ -113,15 +113,15 @@ if test -z "${INITIAL_READONLY_SECTIONS} INITIAL_READONLY_SECTIONS=".interp ${RELOCATING-0} : { *(.interp) }" fi if test -z "$PLT"; then - PLT=".plt ${RELOCATING-0} : { *(.plt) }" + PLT=".plt ${RELOCATING-0} : { *(.plt) *(.iplt)}" fi test -n "${DATA_PLT-${BSS_PLT-text}}" && TEXT_PLT=yes if test -z "$GOT"; then if test -z "$SEPARATE_GOTPLT"; then - GOT=".got ${RELOCATING-0} : { *(.got.plt) *(.got) }" + GOT=".got ${RELOCATING-0} : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }" else - GOT=".got ${RELOCATING-0} : { *(.got) }" - GOTPLT=".got.plt ${RELOCATING-0} : { *(.got.plt) }" + GOT=".got ${RELOCATING-0} : { *(.got) *(.igot) }" + GOTPLT=".got.plt ${RELOCATING-0} : { *(.got.plt) *(.igot.plt) }" fi fi DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }" @@ -354,8 +354,20 @@ EOF fi cat >> ldscripts/dyntmp.$$ <