1 /* Functions to handle creation of Linux archives. 2 Copyright (C) 2007-2012 Red Hat, Inc. 3 This file is part of elfutils. 4 Written by Ulrich Drepper <drepper (at) redhat.com>, 2007. 5 6 This file is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 elfutils is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #ifdef HAVE_CONFIG_H 20 # include <config.h> 21 #endif 22 23 #include <assert.h> 24 #include <error.h> 25 #include <gelf.h> 26 #include <libintl.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <time.h> 30 31 #include <system.h> 32 33 #include "arlib.h" 34 35 36 /* The one symbol table we hanble. */ 37 struct arlib_symtab symtab; 38 39 40 /* Initialize ARLIB_SYMTAB structure. */ 41 void 42 arlib_init (void) 43 { 44 #define obstack_chunk_alloc xmalloc 45 #define obstack_chunk_free free 46 obstack_init (&symtab.symsoffob); 47 obstack_init (&symtab.symsnameob); 48 obstack_init (&symtab.longnamesob); 49 50 /* We add the archive header here as well, that avoids allocating 51 another memory block. */ 52 struct ar_hdr ar_hdr; 53 memcpy (ar_hdr.ar_name, "/ ", sizeof (ar_hdr.ar_name)); 54 /* Using snprintf here has a problem: the call always wants to add a 55 NUL byte. We could use a trick whereby we specify the target 56 buffer size longer than it is and this would not actually fail, 57 since all the fields are consecutive and we fill them in 58 sequence (i.e., the NUL byte gets overwritten). But 59 _FORTIFY_SOURCE=2 would not let us play these games. Therefore 60 we play it safe. */ 61 char tmpbuf[sizeof (ar_hdr.ar_date) + 1]; 62 int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*lld", 63 (int) sizeof (ar_hdr.ar_date), 64 (arlib_deterministic_output ? 0 65 : (long long int) time (NULL))); 66 memcpy (ar_hdr.ar_date, tmpbuf, s); 67 assert ((sizeof (struct ar_hdr) % sizeof (uint32_t)) == 0); 68 69 /* Note the string for the ar_uid and ar_gid cases is longer than 70 necessary. This does not matter since we copy only as much as 71 necessary but it helps the compiler to use the same string for 72 the ar_mode case. */ 73 memcpy (ar_hdr.ar_uid, "0 ", sizeof (ar_hdr.ar_uid)); 74 memcpy (ar_hdr.ar_gid, "0 ", sizeof (ar_hdr.ar_gid)); 75 memcpy (ar_hdr.ar_mode, "0 ", sizeof (ar_hdr.ar_mode)); 76 memcpy (ar_hdr.ar_fmag, ARFMAG, sizeof (ar_hdr.ar_fmag)); 77 78 /* Add the archive header to the file content. */ 79 obstack_grow (&symtab.symsoffob, &ar_hdr, sizeof (ar_hdr)); 80 81 /* The first word in the offset table specifies the size. Create 82 such an entry now. The real value will be filled-in later. For 83 all supported platforms the following is true. */ 84 assert (sizeof (uint32_t) == sizeof (int)); 85 obstack_int_grow (&symtab.symsoffob, 0); 86 87 /* The long name obstack also gets its archive header. As above, 88 some of the input strings are longer than required but we only 89 copy the necessary part. */ 90 memcpy (ar_hdr.ar_name, "// ", sizeof (ar_hdr.ar_name)); 91 memcpy (ar_hdr.ar_date, " ", sizeof (ar_hdr.ar_date)); 92 memcpy (ar_hdr.ar_uid, " ", sizeof (ar_hdr.ar_uid)); 93 memcpy (ar_hdr.ar_gid, " ", sizeof (ar_hdr.ar_gid)); 94 memcpy (ar_hdr.ar_mode, " ", sizeof (ar_hdr.ar_mode)); 95 /* The ar_size field will be filled in later and ar_fmag is already OK. */ 96 obstack_grow (&symtab.longnamesob, &ar_hdr, sizeof (ar_hdr)); 97 98 /* All other members are zero. */ 99 symtab.symsofflen = 0; 100 symtab.symsoff = NULL; 101 symtab.symsnamelen = 0; 102 symtab.symsname = NULL; 103 } 104 105 106 /* Finalize ARLIB_SYMTAB content. */ 107 void 108 arlib_finalize (void) 109 { 110 char tmpbuf[sizeof (((struct ar_hdr *) NULL)->ar_size) + 1]; 111 112 symtab.longnameslen = obstack_object_size (&symtab.longnamesob); 113 if (symtab.longnameslen != sizeof (struct ar_hdr)) 114 { 115 if ((symtab.longnameslen & 1) != 0) 116 { 117 /* Add one more byte to make length even. */ 118 obstack_grow (&symtab.longnamesob, "\n", 1); 119 ++symtab.longnameslen; 120 } 121 122 symtab.longnames = obstack_finish (&symtab.longnamesob); 123 124 int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*zu", 125 (int) sizeof (((struct ar_hdr *) NULL)->ar_size), 126 symtab.longnameslen - sizeof (struct ar_hdr)); 127 memcpy (&((struct ar_hdr *) symtab.longnames)->ar_size, tmpbuf, s); 128 } 129 130 symtab.symsofflen = obstack_object_size (&symtab.symsoffob); 131 assert (symtab.symsofflen % sizeof (uint32_t) == 0); 132 if (symtab.symsofflen != 0) 133 { 134 symtab.symsoff = (uint32_t *) obstack_finish (&symtab.symsoffob); 135 136 /* Fill in the number of offsets now. */ 137 symtab.symsoff[AR_HDR_WORDS] = le_bswap_32 ((symtab.symsofflen 138 - sizeof (struct ar_hdr)) 139 / sizeof (uint32_t) - 1); 140 } 141 142 symtab.symsnamelen = obstack_object_size (&symtab.symsnameob); 143 if ((symtab.symsnamelen & 1) != 0) 144 { 145 /* Add one more NUL byte to make length even. */ 146 obstack_grow (&symtab.symsnameob, "", 1); 147 ++symtab.symsnamelen; 148 } 149 symtab.symsname = obstack_finish (&symtab.symsnameob); 150 151 /* Determine correction for the offsets in the symbol table. */ 152 off_t disp = 0; 153 if (symtab.symsnamelen > 0) 154 disp = symtab.symsofflen + symtab.symsnamelen; 155 if (symtab.longnameslen > sizeof (struct ar_hdr)) 156 disp += symtab.longnameslen; 157 158 if (disp != 0 && symtab.symsoff != NULL) 159 { 160 uint32_t nsyms = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS]); 161 162 for (uint32_t cnt = 1; cnt <= nsyms; ++cnt) 163 { 164 uint32_t val = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS + cnt]); 165 val += disp; 166 symtab.symsoff[AR_HDR_WORDS + cnt] = le_bswap_32 (val); 167 } 168 } 169 170 /* See comment for ar_date above. */ 171 memcpy (&((struct ar_hdr *) symtab.symsoff)->ar_size, tmpbuf, 172 snprintf (tmpbuf, sizeof (tmpbuf), "%-*zu", 173 (int) sizeof (((struct ar_hdr *) NULL)->ar_size), 174 symtab.symsofflen + symtab.symsnamelen 175 - sizeof (struct ar_hdr))); 176 } 177 178 179 /* Free resources for ARLIB_SYMTAB. */ 180 void 181 arlib_fini (void) 182 { 183 obstack_free (&symtab.symsoffob, NULL); 184 obstack_free (&symtab.symsnameob, NULL); 185 obstack_free (&symtab.longnamesob, NULL); 186 } 187 188 189 /* Add name a file offset of a symbol. */ 190 void 191 arlib_add_symref (const char *symname, off_t symoff) 192 { 193 /* For all supported platforms the following is true. */ 194 assert (sizeof (uint32_t) == sizeof (int)); 195 obstack_int_grow (&symtab.symsoffob, (int) le_bswap_32 (symoff)); 196 197 size_t symname_len = strlen (symname) + 1; 198 obstack_grow (&symtab.symsnameob, symname, symname_len); 199 } 200 201 202 /* Add symbols from ELF with value OFFSET to the symbol table SYMTAB. */ 203 void 204 arlib_add_symbols (Elf *elf, const char *arfname, const char *membername, 205 off_t off) 206 { 207 if (sizeof (off) > sizeof (uint32_t) && off > ~((uint32_t) 0)) 208 /* The archive is too big. */ 209 error (EXIT_FAILURE, 0, gettext ("the archive '%s' is too large"), 210 arfname); 211 212 /* We only add symbol tables for ELF files. It makes not much sense 213 to add symbols from executables but we do so for compatibility. 214 For DSOs and executables we use the dynamic symbol table, for 215 relocatable files all the DT_SYMTAB tables. */ 216 if (elf_kind (elf) != ELF_K_ELF) 217 return; 218 219 GElf_Ehdr ehdr_mem; 220 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); 221 if (ehdr == NULL) 222 error (EXIT_FAILURE, 0, gettext ("cannot read ELF header of %s(%s): %s"), 223 arfname, membername, elf_errmsg (-1)); 224 225 GElf_Word symtype; 226 if (ehdr->e_type == ET_REL) 227 symtype = SHT_SYMTAB; 228 else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN) 229 symtype = SHT_DYNSYM; 230 else 231 /* We do not handle that type. */ 232 return; 233 234 /* Iterate over all sections. */ 235 Elf_Scn *scn = NULL; 236 while ((scn = elf_nextscn (elf, scn)) != NULL) 237 { 238 /* Get the section header. */ 239 GElf_Shdr shdr_mem; 240 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 241 if (shdr == NULL) 242 continue; 243 244 if (shdr->sh_type != symtype) 245 continue; 246 247 Elf_Data *data = elf_getdata (scn, NULL); 248 if (data == NULL) 249 continue; 250 251 int nsyms = shdr->sh_size / shdr->sh_entsize; 252 for (int ndx = shdr->sh_info; ndx < nsyms; ++ndx) 253 { 254 GElf_Sym sym_mem; 255 GElf_Sym *sym = gelf_getsym (data, ndx, &sym_mem); 256 if (sym == NULL) 257 continue; 258 259 /* Ignore undefined symbols. */ 260 if (sym->st_shndx == SHN_UNDEF) 261 continue; 262 263 /* Use this symbol. */ 264 const char *symname = elf_strptr (elf, shdr->sh_link, sym->st_name); 265 if (symname != NULL) 266 arlib_add_symref (symname, off); 267 } 268 269 /* Only relocatable files can have more than one symbol table. */ 270 if (ehdr->e_type != ET_REL) 271 break; 272 } 273 } 274