From 6ca4600fb59d1e1ae3dfb872b184ac91f10c473f Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Mon, 12 Jun 2006 22:40:23 +0000 Subject: [PATCH] Don't create INTERP and PHDR program header entry if a DSO is created without a specific interpreter. Ignore duplicate COMDAT group sections. elflint should not complain about anything about *_NONE relocations. Add support to libebl to determine whether given relocation is *_NONE relocation. --- NEWS | 4 ++ backends/ChangeLog | 5 ++ backends/common-reloc.c | 9 ++- libebl/ChangeLog | 9 +++ libebl/Makefile.am | 5 +- libebl/ebl-hooks.h | 5 +- libebl/eblnonerelocp.c | 64 ++++++++++++++++++++ libebl/eblopenbackend.c | 5 +- libebl/libebl.h | 3 + src/ChangeLog | 22 +++++++ src/elflint.c | 4 ++ src/i386_ld.c | 29 ++++++--- src/ld.h | 2 + src/ldgeneric.c | 156 ++++++++++++++++++++++++++++++++---------------- src/ldscript.y | 3 +- 15 files changed, 260 insertions(+), 65 deletions(-) create mode 100644 libebl/eblnonerelocp.c diff --git a/NEWS b/NEWS index d676e73..486cd7e 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ make all installed headers usable in C++ code. readelf: better output format. +elflint: fix tests of dynamic section content. + +ld: Implement --as-needed, --execstack, PT_GNU_STACK. Many small patches. + libdw, libdwfl: handle files without aranges info. Version 0.120: diff --git a/backends/ChangeLog b/backends/ChangeLog index 33d52a2..c054c58 100644 --- a/backends/ChangeLog +++ b/backends/ChangeLog @@ -1,3 +1,8 @@ +2006-06-12 Ulrich Drepper + + * common-reloc.c (none_reloc_p): New function. + (init_reloc): Hoop it up. + 2006-02-22 Roland McGrath * ppc64_retval.c (SVR4_STRUCT_RETURN): New macro. diff --git a/backends/common-reloc.c b/backends/common-reloc.c index b3b7553..9b95655 100644 --- a/backends/common-reloc.c +++ b/backends/common-reloc.c @@ -1,5 +1,5 @@ /* Common code for ebl reloc functions. - Copyright (C) 2005 Red Hat, Inc. + Copyright (C) 2005, 2006 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -115,6 +115,12 @@ EBLHOOK(copy_reloc_p) (int reloc) return reloc == R_TYPE (COPY); } +bool +EBLHOOK(none_reloc_p) (int reloc) +{ + return reloc == R_TYPE (NONE); +} + static void EBLHOOK(init_reloc) (Ebl *ebl) { @@ -122,4 +128,5 @@ EBLHOOK(init_reloc) (Ebl *ebl) ebl->reloc_type_check = EBLHOOK(reloc_type_check); ebl->reloc_valid_use = EBLHOOK(reloc_valid_use); ebl->copy_reloc_p = EBLHOOK(copy_reloc_p); + ebl->none_reloc_p = EBLHOOK(none_reloc_p); } diff --git a/libebl/ChangeLog b/libebl/ChangeLog index 01dba09..1d9fcfd 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -1,3 +1,12 @@ +2006-06-12 Ulrich Drepper + + * Makefile.am (gen_SOURCES): Add eblnonerelocp.c. + * eblnonerelocp.c: New file. + * ebl-hooks.c: Add none_reloc_p. + * eblopenbackend.c (default_none_reloc_p): New function. + (fill_defaults): Hook it up. + * libebl.h: Declare ebl_none_reloc_p. + 2006-05-27 Ulrich Drepper * libebl.h: Add extern "C". diff --git a/libebl/Makefile.am b/libebl/Makefile.am index 483fd13..9826927 100644 --- a/libebl/Makefile.am +++ b/libebl/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to create Makefile.in ## -## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. +## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. ## This file is part of Red Hat elfutils. ## ## Red Hat elfutils is free software; you can redistribute it and/or modify @@ -55,7 +55,8 @@ gen_SOURCES = eblopenbackend.c eblclosebackend.c eblstrtab.c \ eblcorenote.c eblobjnote.c ebldebugscnp.c \ eblgotpcreloccheck.c eblcopyrelocp.c eblsectionstripp.c \ eblelfclass.c eblelfdata.c eblelfmachine.c \ - ebl_check_special_symbol.c eblbsspltp.c eblretval.c eblregname.c + ebl_check_special_symbol.c eblbsspltp.c eblretval.c \ + eblregname.c eblnonerelocp.c libebl_a_SOURCES = $(gen_SOURCES) diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h index 22d3873..4227c24 100644 --- a/libebl/ebl-hooks.h +++ b/libebl/ebl-hooks.h @@ -1,5 +1,5 @@ /* Backend hook signatures internal interface for libebl. - Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -116,6 +116,9 @@ bool EBLHOOK(debugscn_p) (const char *); /* Check whether given relocation is a copy relocation. */ bool EBLHOOK(copy_reloc_p) (int); +/* Check whether given relocation is a no-op relocation. */ +bool EBLHOOK(none_reloc_p) (int); + /* Check whether given symbol's value is ok despite normal checks. */ bool EBLHOOK(check_special_symbol) (Elf *, GElf_Ehdr *, const GElf_Sym *, const char *, const GElf_Shdr *); diff --git a/libebl/eblnonerelocp.c b/libebl/eblnonerelocp.c new file mode 100644 index 0000000..3d62a0b --- /dev/null +++ b/libebl/eblnonerelocp.c @@ -0,0 +1,64 @@ +/* Check whether given relocation is a copy relocation. + Copyright (C) 2006 Red Hat, Inc. + This file is part of Red Hat elfutils. + Written by Ulrich Drepper , 2006. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +bool +ebl_none_reloc_p (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl->none_reloc_p (reloc); +} diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c index 03fa99e..092068c 100644 --- a/libebl/eblopenbackend.c +++ b/libebl/eblopenbackend.c @@ -1,5 +1,5 @@ /* Generate ELF backend handle. - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -190,6 +190,7 @@ static bool default_object_note (const char *name, uint32_t type, uint32_t descsz, const char *desc); static bool default_debugscn_p (const char *name); static bool default_copy_reloc_p (int reloc); +static bool default_none_reloc_p (int reloc); static bool default_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, const GElf_Sym *sym, const char *name, @@ -229,6 +230,7 @@ fill_defaults (Ebl *result) result->object_note = default_object_note; result->debugscn_p = default_debugscn_p; result->copy_reloc_p = default_copy_reloc_p; + result->none_reloc_p = default_none_reloc_p; result->check_special_symbol = default_check_special_symbol; result->bss_plt_p = default_bss_plt_p; result->return_value_location = default_return_value_location; @@ -605,6 +607,7 @@ default_copy_reloc_p (int reloc __attribute__ ((unused))) { return false; } +strong_alias (default_copy_reloc_p, default_none_reloc_p) static bool default_check_special_symbol (Elf *elf __attribute__ ((unused)), diff --git a/libebl/libebl.h b/libebl/libebl.h index 3014634..c27dfd4 100644 --- a/libebl/libebl.h +++ b/libebl/libebl.h @@ -189,6 +189,9 @@ extern bool ebl_debugscn_p (Ebl *ebl, const char *name); /* Check whether given relocation is a copy relocation. */ extern bool ebl_copy_reloc_p (Ebl *ebl, int reloc); +/* Check whether given relocation is a no-op relocation. */ +extern bool ebl_none_reloc_p (Ebl *ebl, int reloc); + /* Check whether section should be stripped. */ extern bool ebl_section_strip_p (Ebl *ebl, const GElf_Ehdr *ehdr, const GElf_Shdr *shdr, const char *name, diff --git a/src/ChangeLog b/src/ChangeLog index 74ea2bf..c7c113e 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,25 @@ +2006-06-12 Ulrich Drepper + + * ldgeneric.c (ld_generic_generate_sections): Don't create .interp + section if creating a DSO and no interpreter is given. + (ld_generic_create_outfile): Don't store reference to symbols in + discarded COMDAT groups. Don't create PHDR and INTERP program header + for DSO if no interpreter is specified. + * ldscript.y (content): If a DSO is created don't set default + interpreter from linker script. + + * i386_ld.c (elf_i386_count_relocations): Do not add relocations + for symbols in discarded COMDAT groups. + (elf_i386_create_relocations): Likewise. + * ld.h (struct scninfo): Add unused_comdat. + * ldgeneric.c (add_section): Also check group signature when + matching COMDAT sections. + (add_relocatable_file): Ignore symbols in COMDAT group which are + discarded. + + * elflint.c (check_one_reloc): For *_NONE relocs only check type + and symbol reference. + 2006-06-11 Ulrich Drepper * elflint.c (check_dynamic): Fix checking value of tags which are diff --git a/src/elflint.c b/src/elflint.c index b1eb5d3..cd335fe 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -1170,6 +1170,10 @@ section [%2d] '%s': relocation %zu: relocation type invalid for the file type\n" section [%2d] '%s': relocation %zu: invalid symbol index\n"), idx, section_name (ebl, idx), cnt); + /* No more tests if this is a no-op relocation. */ + if (ebl_none_reloc_p (ebl, GELF_R_TYPE (r_info))) + return; + if (ebl_gotpc_reloc_check (ebl, GELF_R_TYPE (r_info))) { const char *name; diff --git a/src/i386_ld.c b/src/i386_ld.c index d1a213d..a0c77db 100644 --- a/src/i386_ld.c +++ b/src/i386_ld.c @@ -525,6 +525,11 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo) { Elf32_Word r_sym = XELF_R_SYM (rel->r_info); + /* Symbols in COMDAT group sections which are discarded do + not have to be relocated. */ + if (unlikely (scninfo->fileinfo->symref[r_sym] == NULL)) + continue; + switch (XELF_R_TYPE (rel->r_info)) { case R_386_GOT32: @@ -717,16 +722,24 @@ elf_i386_create_relocations (struct ld_state *statep, section in the output file and the addend. */ value = scninfo[sym->st_shndx].offset + sym->st_value; } - else if (symref[idx]->in_dso) + else { - /* MERGE.VALUE contains the PLT index. We have to add 1 since - there is this one special PLT entry at the beginning. */ - assert (symref[idx]->merge.value != 0 - || symref[idx]->type != STT_FUNC); - value = pltaddr + symref[idx]->merge.value * PLT_ENTRY_SIZE; + if (symref[idx] == NULL) + /* Symbol in ignored COMDAT group section. */ + continue; + + if (symref[idx]->in_dso) + { + /* MERGE.VALUE contains the PLT index. We have to + add 1 since there is this one special PLT entry + at the beginning. */ + assert (symref[idx]->merge.value != 0 + || symref[idx]->type != STT_FUNC); + value = pltaddr + symref[idx]->merge.value * PLT_ENTRY_SIZE; + } + else + value = symref[idx]->merge.value; } - else - value = symref[idx]->merge.value; /* Address of the relocated memory in the data buffer. */ void *relloc = (char *) data->d_buf + rel->r_offset; diff --git a/src/ld.h b/src/ld.h index 36afca1..bdabee4 100644 --- a/src/ld.h +++ b/src/ld.h @@ -174,6 +174,8 @@ struct usedfiles Elf32_Word allsectionsidx; /* True if the section is used. */ bool used; + /* True if section is an unused COMDAT section. */ + bool unused_comdat; /* Section group number. This is the index of the SHT_GROUP section. */ Elf32_Word grpid; /* Pointer back to the containing file information structure. */ diff --git a/src/ldgeneric.c b/src/ldgeneric.c index c089e0b..22fac22 100644 --- a/src/ldgeneric.c +++ b/src/ldgeneric.c @@ -991,7 +991,36 @@ add_section (struct usedfiles *fileinfo, struct scninfo *scninfo) } /* XXX Possibly unaligned memory access. */ - is_comdat = ((Elf32_Word *) grpscndata->d_buf)[0] & GRP_COMDAT; + if ((((Elf32_Word *) grpscndata->d_buf)[0] & GRP_COMDAT) != 0) + { + /* We have to compare the group signatures. There might + be sections with the same name but belonging to + groups with different signatures. This means we have + to compare the new group signature with all those + already collected. There might also be some + non-group sections in the mix. */ + struct scninfo *runp = queued->last; + do + { + if (SCNINFO_SHDR (runp->shdr).sh_flags & SHF_GROUP) + { + struct scninfo *grpscn2 + = find_section_group (runp->fileinfo, + elf_ndxscn (runp->scn), + &grpscndata); + + if (strcmp (grpscn->symbols->name, + grpscn2->symbols->name) == 0) + { + scninfo->unused_comdat = is_comdat = true; + break; + } + } + + runp = runp->next; + } + while (runp != queued->last); + } } if (!is_comdat) @@ -1378,6 +1407,11 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype) if (unlikely (shndx == SHN_ABS) && secttype == SHT_DYNSYM) continue; + if ((shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE) + && fileinfo->scninfo[shndx].unused_comdat) + /* The symbol is not used. */ + continue; + /* If the DSO uses symbols determine whether this is the default version. Otherwise we'll ignore the symbol. */ if (versymdata != NULL) @@ -2302,8 +2336,9 @@ ld_generic_generate_sections (struct ld_state *statep) bool need_version = false; /* First the .interp section. */ - new_generated_scn (scn_dot_interp, ".interp", SHT_PROGBITS, SHF_ALLOC, - 0, 1); + if (ld_state.interp != NULL || ld_state.file_type != dso_file_type) + new_generated_scn (scn_dot_interp, ".interp", SHT_PROGBITS, SHF_ALLOC, + 0, 1); /* Now the .dynamic section. */ new_generated_scn (scn_dot_dynamic, ".dynamic", SHT_DYNAMIC, @@ -4739,23 +4774,24 @@ section index too large in dynamic symbol table")); Find the symbol if this has not happened yet. We do not need the information for local symbols. */ if (defp == NULL && cnt >= file->nlocalsymbols) - { - defp = file->symref[cnt]; - assert (defp != NULL); - } + defp = file->symref[cnt]; - /* Store the reference to the symbol record. The - sorting code will have to keep this array in the - correct order, too. */ - ndxtosym[nsym] = defp; - - /* One more entry finished. */ - if (cnt >= file->nlocalsymbols) + /* Ignore symbols in discarded COMDAT group sections. */ + if (defp != NULL) { - assert (file->symref[cnt]->outsymidx == 0); - file->symref[cnt]->outsymidx = nsym; + /* Store the reference to the symbol record. The + sorting code will have to keep this array in the + correct order, too. */ + ndxtosym[nsym] = defp; + + /* One more entry finished. */ + if (cnt >= file->nlocalsymbols) + { + assert (file->symref[cnt]->outsymidx == 0); + file->symref[cnt]->outsymidx = nsym; + } + file->symindirect[cnt] = nsym++; } - file->symindirect[cnt] = nsym++; } } while ((file = file->next) != ld_state.relfiles->next); @@ -5624,10 +5660,16 @@ cannot create hash table section for output file: %s"), /* Add the number of SHT_NOTE sections. We counted them earlier. */ nphdr += ld_state.nnotesections; - /* If we create a DSO or the file is linked against DSOs we have three - more entries: INTERP, PHDR, DYNAMIC. */ + /* If we create a DSO or the file is linked against DSOs we have + at least one more entry: DYNAMIC. If an interpreter is + specified we add PHDR and INTERP, too. */ if (dynamically_linked_p ()) - nphdr += 3; + { + ++nphdr; + + if (ld_state.interp != NULL || ld_state.file_type != dso_file_type) + nphdr += 2; + } /* Create the program header structure. */ if (xelf_newphdr (ld_state.outelf, nphdr) == 0) @@ -5655,7 +5697,14 @@ cannot create hash table section for output file: %s"), addr = shdr->sh_offset; /* The index of the first loadable segment. */ - nphdr = 1 + (dynamically_linked_p () == true) * 2; + nphdr = 0; + if (dynamically_linked_p ()) + { + ++nphdr; + if (ld_state.interp != NULL + || ld_state.file_type != dso_file_type) + nphdr += 2; + } segment = ld_state.output_segments; while (segment != NULL) @@ -5813,18 +5862,6 @@ internal error: nobits section follows nobits section")); xelf_getehdr (ld_state.outelf, ehdr); assert (ehdr != NULL); - xelf_getphdr_ptr (ld_state.outelf, 0, phdr); - phdr->p_type = PT_PHDR; - phdr->p_offset = ehdr->e_phoff; - phdr->p_vaddr = ld_state.output_segments->addr + phdr->p_offset; - phdr->p_paddr = phdr->p_vaddr; - phdr->p_filesz = ehdr->e_phnum * ehdr->e_phentsize; - phdr->p_memsz = phdr->p_filesz; - phdr->p_flags = 0; /* No need to set PF_R or so. */ - phdr->p_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); - (void) xelf_update_phdr (ld_state.outelf, 0, phdr); - - /* Add the stack information. */ xelf_getphdr_ptr (ld_state.outelf, nphdr, phdr); phdr->p_type = PT_GNU_STACK; @@ -5941,24 +5978,41 @@ internal error: nobits section follows nobits section")); { Elf_Scn *outscn; - assert (ld_state.interpscnidx != 0); - xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.interpscnidx), - shdr); - assert (shdr != NULL); + int idx = 0; + if (ld_state.interp != NULL || ld_state.file_type != dso_file_type) + { + assert (ld_state.interpscnidx != 0); + xelf_getshdr (elf_getscn (ld_state.outelf, + ld_state.interpscnidx), shdr); + assert (shdr != NULL); - /* The interpreter string. */ - // XXX Do we need to support files (DSOs) without interpreters? - xelf_getphdr_ptr (ld_state.outelf, 1, phdr); - phdr->p_type = PT_INTERP; - phdr->p_offset = shdr->sh_offset; - phdr->p_vaddr = shdr->sh_addr; - phdr->p_paddr = phdr->p_vaddr; - phdr->p_filesz = shdr->sh_size; - phdr->p_memsz = phdr->p_filesz; - phdr->p_flags = 0; /* No need to set PF_R or so. */ - phdr->p_align = 1; /* It's a string. */ + xelf_getphdr_ptr (ld_state.outelf, idx, phdr); + phdr->p_type = PT_PHDR; + phdr->p_offset = ehdr->e_phoff; + phdr->p_vaddr = ld_state.output_segments->addr + phdr->p_offset; + phdr->p_paddr = phdr->p_vaddr; + phdr->p_filesz = ehdr->e_phnum * ehdr->e_phentsize; + phdr->p_memsz = phdr->p_filesz; + phdr->p_flags = 0; /* No need to set PF_R or so. */ + phdr->p_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); + + (void) xelf_update_phdr (ld_state.outelf, idx, phdr); + ++idx; + + /* The interpreter string. */ + xelf_getphdr_ptr (ld_state.outelf, idx, phdr); + phdr->p_type = PT_INTERP; + phdr->p_offset = shdr->sh_offset; + phdr->p_vaddr = shdr->sh_addr; + phdr->p_paddr = phdr->p_vaddr; + phdr->p_filesz = shdr->sh_size; + phdr->p_memsz = phdr->p_filesz; + phdr->p_flags = 0; /* No need to set PF_R or so. */ + phdr->p_align = 1; /* It's a string. */ - (void) xelf_update_phdr (ld_state.outelf, 1, phdr); + (void) xelf_update_phdr (ld_state.outelf, idx, phdr); + ++idx; + } /* The pointer to the dynamic section. We this we need to get the information for the dynamic section first. */ @@ -5967,7 +6021,7 @@ internal error: nobits section follows nobits section")); xelf_getshdr (outscn, shdr); assert (shdr != NULL); - xelf_getphdr_ptr (ld_state.outelf, 2, phdr); + xelf_getphdr_ptr (ld_state.outelf, idx, phdr); phdr->p_type = PT_DYNAMIC; phdr->p_offset = shdr->sh_offset; phdr->p_vaddr = shdr->sh_addr; @@ -5977,7 +6031,7 @@ internal error: nobits section follows nobits section")); phdr->p_flags = 0; /* No need to set PF_R or so. */ phdr->p_align = shdr->sh_addralign; - (void) xelf_update_phdr (ld_state.outelf, 2, phdr); + (void) xelf_update_phdr (ld_state.outelf, idx, phdr); /* Fill in the reference to the .dynstr section. */ assert (ld_state.dynstrscnidx != 0); diff --git a/src/ldscript.y b/src/ldscript.y index 764b415..252f9d4 100644 --- a/src/ldscript.y +++ b/src/ldscript.y @@ -165,7 +165,8 @@ content: kENTRY '(' kID ')' ';' } | kINTERP '(' filename_id ')' ';' { - if (likely (ld_state.interp == NULL)) + if (likely (ld_state.interp == NULL) + && ld_state.file_type != dso_file_type) ld_state.interp = $3; } | kSEGMENT kMODE '{' outputsections '}' -- 2.7.4