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