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