1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <string.h> 31 #include <link.h> 32 #include "debug.h" 33 #include "msg.h" 34 #include "_libld.h" 35 36 37 /* 38 * Given a group signature symbol - scan through the global list 39 * of GROUP sections to determine if we have a conflict/discard. 40 * If this is the first time we see a group signature - add it to the 41 * global list. 42 * 43 * Returns: 44 * 0 - Group kept and added to global list. 45 * 1 - Group should be discarded. 46 */ 47 uintptr_t 48 scan_global_groups(Group_desc * gdesc, Ofl_desc * ofl) 49 { 50 Group_desc * _gdesc; 51 Listnode * lnp; 52 53 /* 54 * Scan through global list - if we find a group of the 55 * same name - we return 0 saying this new group should 56 * be discarded (since only COMDAT's get here currently). 57 */ 58 for (LIST_TRAVERSE(&ofl->ofl_groups, lnp, _gdesc)) 59 if (strcmp(_gdesc->gd_symname, gdesc->gd_symname) == 0) { 60 gdesc->gd_flags |= GRP_FLG_DISCARD; 61 return (1); 62 } 63 64 if (list_appendc(&ofl->ofl_groups, gdesc) == 0) 65 return (S_ERROR); 66 67 return (0); 68 } 69 70 71 Group_desc * 72 get_group_desc(Ofl_desc *ofl, Is_desc *isp) 73 { 74 Ifl_desc *ifl = isp->is_file; 75 Elf *elf = ifl->ifl_elf; 76 uint_t scnndx = isp->is_scnndx; 77 Group_desc *gdesc; 78 Listnode *lnp; 79 80 81 /* 82 * If this is the first section of with the SHF_GROUP flag 83 * set - then we havn't yet scanned for - and found our 84 * group sections. If thats so - do it now. 85 */ 86 if (ifl->ifl_groups.head == 0) { 87 Elf_Scn *scn = 0; 88 while (scn = elf_nextscn(elf, scn)) { 89 Shdr *shdr; 90 Shdr *_shdr; 91 Sym *sym; 92 const char *symname; 93 Elf_Scn *_scn; 94 Elf_Data *data; 95 96 shdr = elf_getshdr(scn); 97 if (shdr->sh_type != SHT_GROUP) 98 continue; 99 100 /* 101 * Confirm that the sh_link points to a 102 * valid section. 103 */ 104 if ((shdr->sh_link == SHN_UNDEF) || 105 (shdr->sh_link >= ifl->ifl_shnum)) { 106 eprintf(ERR_FATAL, MSG_INTL(MSG_FIL_INVSHLINK), 107 ifl->ifl_name, elf_strptr(elf, 108 ifl->ifl_shstrndx, 109 shdr->sh_name), 110 EC_XWORD(shdr->sh_link)); 111 ofl->ofl_flags |= FLG_OF_FATAL; 112 continue; 113 } 114 115 if (shdr->sh_entsize == 0) { 116 eprintf(ERR_FATAL, 117 MSG_INTL(MSG_FIL_INVSHENTSIZE), 118 ifl->ifl_name, elf_strptr(elf, 119 ifl->ifl_shstrndx, 120 shdr->sh_name), 121 EC_XWORD(shdr->sh_entsize)); 122 ofl->ofl_flags |= FLG_OF_FATAL; 123 continue; 124 } 125 126 /* 127 * Get associated symbol table 128 */ 129 _scn = elf_getscn(elf, shdr->sh_link); 130 _shdr = elf_getshdr(_scn); 131 132 /* 133 * Sanity check the sh_link field (which points to 134 * a symbol table entry) against the size of the 135 * symbol table. 136 */ 137 if ((shdr->sh_info == SHN_UNDEF) || 138 (shdr->sh_info >= (Word)(_shdr->sh_size / 139 _shdr->sh_entsize))) { 140 eprintf(ERR_FATAL, MSG_INTL(MSG_FIL_INVSHINFO), 141 ifl->ifl_name, elf_strptr(elf, 142 ifl->ifl_shstrndx, 143 shdr->sh_name), 144 EC_XWORD(shdr->sh_info)); 145 ofl->ofl_flags |= FLG_OF_FATAL; 146 continue; 147 } 148 149 data = elf_getdata(_scn, 0); 150 sym = data->d_buf; 151 sym += shdr->sh_info; 152 symname = elf_strptr(elf, _shdr->sh_link, sym->st_name); 153 154 if ((gdesc = libld_calloc(sizeof (Group_desc), 1)) == 0) 155 return ((Group_desc *)S_ERROR); 156 157 gdesc->gd_gsectname = elf_strptr(elf, 158 ifl->ifl_shstrndx, shdr->sh_name); 159 gdesc->gd_symname = symname; 160 gdesc->gd_sym = sym; 161 gdesc->gd_scn = scn; 162 data = elf_getdata(scn, 0); 163 gdesc->gd_groupdata = data->d_buf; 164 gdesc->gd_gdcnt = data->d_size / sizeof (Word); 165 /* 166 * If this group is a COMDAT group - then we 167 * need to find the 'signature' symbol to determine 168 * if this is group is to be kept or discarded. 169 */ 170 if (gdesc->gd_groupdata[0] & GRP_COMDAT) { 171 if ((ELF_ST_BIND(sym->st_info) != STB_LOCAL) && 172 (sym->st_shndx != SHN_UNDEF)) { 173 if (scan_global_groups(gdesc, ofl) 174 == S_ERROR) 175 return ((Group_desc *)S_ERROR); 176 } 177 } 178 if (list_appendc(&ifl->ifl_groups, gdesc) == 0) 179 return ((Group_desc *)S_ERROR); 180 } 181 } 182 183 /* 184 * Now we scan through the GROUP sections associated with 185 * this file - to find the matching group section. 186 */ 187 for (LIST_TRAVERSE(&ifl->ifl_groups, lnp, gdesc)) { 188 size_t i; 189 Word * gdata; 190 if (isp->is_shdr->sh_type == SHT_GROUP) { 191 if ((size_t)isp->is_scnndx == 192 elf_ndxscn(gdesc->gd_scn)) { 193 isp->is_group = gdesc; 194 return (gdesc); 195 } 196 continue; 197 } 198 199 gdata = gdesc->gd_groupdata; 200 for (i = 1; i < gdesc->gd_gdcnt; i++) { 201 if (gdata[i] == scnndx) { 202 isp->is_group = gdesc; 203 return (gdesc); 204 } 205 } 206 } 207 eprintf(ERR_FATAL, MSG_INTL(MSG_ELF_NOGROUPSECT), ifl->ifl_name, 208 isp->is_name); 209 ofl->ofl_flags |= FLG_OF_FATAL; 210 return ((Group_desc *)0); 211 } 212