blob: a6521e307b11c86a7e612a7a72eab0c510c90fa3 [file] [log] [blame]
Ulrich Drepperce0bdb62007-02-05 07:13:52 +00001/* Functions to handle creation of Linux archives.
Mark Wielaardd5afff82016-11-10 18:45:02 +01002 Copyright (C) 2007-2012, 2016 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperce0bdb62007-02-05 07:13:52 +00004 Written by Ulrich Drepper <drepper@redhat.com>, 2007.
5
Mark Wielaardde2ed972012-06-05 17:15:16 +02006 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.
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000010
Mark Wielaardde2ed972012-06-05 17:15:16 +020011 elfutils is distributed in the hope that it will be useful, but
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000012 WITHOUT ANY WARRANTY; without even the implied warranty of
Mark Wielaardde2ed972012-06-05 17:15:16 +020013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000015
Mark Wielaardde2ed972012-06-05 17:15:16 +020016 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/>. */
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000018
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#include <assert.h>
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000024#include <gelf.h>
Mark Wielaardd5afff82016-11-10 18:45:02 +010025#include <inttypes.h>
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000026#include <libintl.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <time.h>
30
Akihiko Odaki60b2bf12016-10-11 23:06:48 +090031#include <libeu.h>
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000032
Ross Burtone893aab2018-07-04 12:11:08 +010033#include "system.h"
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000034#include "arlib.h"
35
36
Ulrich Drepper0fe63532007-02-05 21:05:51 +000037/* The one symbol table we hanble. */
38struct arlib_symtab symtab;
39
40
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000041/* Initialize ARLIB_SYMTAB structure. */
42void
Ulrich Drepper0fe63532007-02-05 21:05:51 +000043arlib_init (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000044{
45#define obstack_chunk_alloc xmalloc
46#define obstack_chunk_free free
Ulrich Drepper0fe63532007-02-05 21:05:51 +000047 obstack_init (&symtab.symsoffob);
48 obstack_init (&symtab.symsnameob);
49 obstack_init (&symtab.longnamesob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000050
51 /* We add the archive header here as well, that avoids allocating
52 another memory block. */
53 struct ar_hdr ar_hdr;
54 memcpy (ar_hdr.ar_name, "/ ", sizeof (ar_hdr.ar_name));
55 /* Using snprintf here has a problem: the call always wants to add a
56 NUL byte. We could use a trick whereby we specify the target
57 buffer size longer than it is and this would not actually fail,
Marek Polaceked526182011-04-15 11:41:32 +020058 since all the fields are consecutive and we fill them in
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000059 sequence (i.e., the NUL byte gets overwritten). But
60 _FORTIFY_SOURCE=2 would not let us play these games. Therefore
61 we play it safe. */
62 char tmpbuf[sizeof (ar_hdr.ar_date) + 1];
Mark Wielaard03d76f42013-11-09 16:45:22 +010063 int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*lld",
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000064 (int) sizeof (ar_hdr.ar_date),
Roland McGrath85924782012-01-20 11:40:59 -080065 (arlib_deterministic_output ? 0
Mark Wielaard03d76f42013-11-09 16:45:22 +010066 : (long long int) time (NULL)));
67 memcpy (ar_hdr.ar_date, tmpbuf, s);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000068 assert ((sizeof (struct ar_hdr) % sizeof (uint32_t)) == 0);
69
70 /* Note the string for the ar_uid and ar_gid cases is longer than
71 necessary. This does not matter since we copy only as much as
72 necessary but it helps the compiler to use the same string for
73 the ar_mode case. */
74 memcpy (ar_hdr.ar_uid, "0 ", sizeof (ar_hdr.ar_uid));
75 memcpy (ar_hdr.ar_gid, "0 ", sizeof (ar_hdr.ar_gid));
76 memcpy (ar_hdr.ar_mode, "0 ", sizeof (ar_hdr.ar_mode));
77 memcpy (ar_hdr.ar_fmag, ARFMAG, sizeof (ar_hdr.ar_fmag));
78
79 /* Add the archive header to the file content. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +000080 obstack_grow (&symtab.symsoffob, &ar_hdr, sizeof (ar_hdr));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000081
82 /* The first word in the offset table specifies the size. Create
83 such an entry now. The real value will be filled-in later. For
84 all supported platforms the following is true. */
85 assert (sizeof (uint32_t) == sizeof (int));
Ulrich Drepper0fe63532007-02-05 21:05:51 +000086 obstack_int_grow (&symtab.symsoffob, 0);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000087
88 /* The long name obstack also gets its archive header. As above,
89 some of the input strings are longer than required but we only
90 copy the necessary part. */
91 memcpy (ar_hdr.ar_name, "// ", sizeof (ar_hdr.ar_name));
92 memcpy (ar_hdr.ar_date, " ", sizeof (ar_hdr.ar_date));
93 memcpy (ar_hdr.ar_uid, " ", sizeof (ar_hdr.ar_uid));
94 memcpy (ar_hdr.ar_gid, " ", sizeof (ar_hdr.ar_gid));
95 memcpy (ar_hdr.ar_mode, " ", sizeof (ar_hdr.ar_mode));
96 /* The ar_size field will be filled in later and ar_fmag is already OK. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +000097 obstack_grow (&symtab.longnamesob, &ar_hdr, sizeof (ar_hdr));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000098
99 /* All other members are zero. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000100 symtab.symsofflen = 0;
101 symtab.symsoff = NULL;
102 symtab.symsnamelen = 0;
103 symtab.symsname = NULL;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000104}
105
106
107/* Finalize ARLIB_SYMTAB content. */
108void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000109arlib_finalize (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000110{
Mark Wielaardd5afff82016-11-10 18:45:02 +0100111 /* Note that the size is stored as decimal string in 10 chars,
112 without zero terminator (we add + 1 here only so snprintf can
113 put it at the end, we then don't use it when we memcpy it). */
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000114 char tmpbuf[sizeof (((struct ar_hdr *) NULL)->ar_size) + 1];
115
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000116 symtab.longnameslen = obstack_object_size (&symtab.longnamesob);
117 if (symtab.longnameslen != sizeof (struct ar_hdr))
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000118 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000119 if ((symtab.longnameslen & 1) != 0)
120 {
121 /* Add one more byte to make length even. */
122 obstack_grow (&symtab.longnamesob, "\n", 1);
123 ++symtab.longnameslen;
124 }
125
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000126 symtab.longnames = obstack_finish (&symtab.longnamesob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000127
Mark Wielaardd5afff82016-11-10 18:45:02 +0100128 int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*" PRIu32 "",
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000129 (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
Mark Wielaardd5afff82016-11-10 18:45:02 +0100130 (uint32_t) (symtab.longnameslen - sizeof (struct ar_hdr)));
Mark Wielaard03d76f42013-11-09 16:45:22 +0100131 memcpy (&((struct ar_hdr *) symtab.longnames)->ar_size, tmpbuf, s);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000132 }
133
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000134 symtab.symsofflen = obstack_object_size (&symtab.symsoffob);
135 assert (symtab.symsofflen % sizeof (uint32_t) == 0);
136 if (symtab.symsofflen != 0)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000137 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000138 symtab.symsoff = (uint32_t *) obstack_finish (&symtab.symsoffob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000139
140 /* Fill in the number of offsets now. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000141 symtab.symsoff[AR_HDR_WORDS] = le_bswap_32 ((symtab.symsofflen
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000142 - sizeof (struct ar_hdr))
143 / sizeof (uint32_t) - 1);
144 }
145
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000146 symtab.symsnamelen = obstack_object_size (&symtab.symsnameob);
147 if ((symtab.symsnamelen & 1) != 0)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000148 {
149 /* Add one more NUL byte to make length even. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000150 obstack_grow (&symtab.symsnameob, "", 1);
151 ++symtab.symsnamelen;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000152 }
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000153 symtab.symsname = obstack_finish (&symtab.symsnameob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000154
155 /* Determine correction for the offsets in the symbol table. */
156 off_t disp = 0;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000157 if (symtab.symsnamelen > 0)
158 disp = symtab.symsofflen + symtab.symsnamelen;
159 if (symtab.longnameslen > sizeof (struct ar_hdr))
160 disp += symtab.longnameslen;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000161
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000162 if (disp != 0 && symtab.symsoff != NULL)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000163 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000164 uint32_t nsyms = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS]);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000165
166 for (uint32_t cnt = 1; cnt <= nsyms; ++cnt)
167 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000168 uint32_t val = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS + cnt]);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000169 val += disp;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000170 symtab.symsoff[AR_HDR_WORDS + cnt] = le_bswap_32 (val);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000171 }
172 }
173
174 /* See comment for ar_date above. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000175 memcpy (&((struct ar_hdr *) symtab.symsoff)->ar_size, tmpbuf,
Mark Wielaardd5afff82016-11-10 18:45:02 +0100176 snprintf (tmpbuf, sizeof (tmpbuf), "%-*" PRIu32 "",
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000177 (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
Mark Wielaardd5afff82016-11-10 18:45:02 +0100178 (uint32_t) (symtab.symsofflen + symtab.symsnamelen
179 - sizeof (struct ar_hdr))));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000180}
181
182
183/* Free resources for ARLIB_SYMTAB. */
184void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000185arlib_fini (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000186{
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000187 obstack_free (&symtab.symsoffob, NULL);
188 obstack_free (&symtab.symsnameob, NULL);
189 obstack_free (&symtab.longnamesob, NULL);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000190}
191
192
193/* Add name a file offset of a symbol. */
194void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000195arlib_add_symref (const char *symname, off_t symoff)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000196{
197 /* For all supported platforms the following is true. */
198 assert (sizeof (uint32_t) == sizeof (int));
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000199 obstack_int_grow (&symtab.symsoffob, (int) le_bswap_32 (symoff));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000200
201 size_t symname_len = strlen (symname) + 1;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000202 obstack_grow (&symtab.symsnameob, symname, symname_len);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000203}
204
205
206/* Add symbols from ELF with value OFFSET to the symbol table SYMTAB. */
207void
208arlib_add_symbols (Elf *elf, const char *arfname, const char *membername,
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000209 off_t off)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000210{
211 if (sizeof (off) > sizeof (uint32_t) && off > ~((uint32_t) 0))
212 /* The archive is too big. */
213 error (EXIT_FAILURE, 0, gettext ("the archive '%s' is too large"),
214 arfname);
215
216 /* We only add symbol tables for ELF files. It makes not much sense
217 to add symbols from executables but we do so for compatibility.
218 For DSOs and executables we use the dynamic symbol table, for
219 relocatable files all the DT_SYMTAB tables. */
220 if (elf_kind (elf) != ELF_K_ELF)
221 return;
222
223 GElf_Ehdr ehdr_mem;
224 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
225 if (ehdr == NULL)
226 error (EXIT_FAILURE, 0, gettext ("cannot read ELF header of %s(%s): %s"),
227 arfname, membername, elf_errmsg (-1));
228
229 GElf_Word symtype;
230 if (ehdr->e_type == ET_REL)
231 symtype = SHT_SYMTAB;
232 else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)
233 symtype = SHT_DYNSYM;
234 else
235 /* We do not handle that type. */
236 return;
237
238 /* Iterate over all sections. */
239 Elf_Scn *scn = NULL;
240 while ((scn = elf_nextscn (elf, scn)) != NULL)
241 {
242 /* Get the section header. */
243 GElf_Shdr shdr_mem;
244 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
245 if (shdr == NULL)
246 continue;
247
248 if (shdr->sh_type != symtype)
249 continue;
250
251 Elf_Data *data = elf_getdata (scn, NULL);
252 if (data == NULL)
253 continue;
254
Mark Wielaard2b16a9b2018-10-18 19:01:52 +0200255 if (shdr->sh_entsize == 0)
256 continue;
257
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000258 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)
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000273 arlib_add_symref (symname, off);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000274 }
275
276 /* Only relocatable files can have more than one symbol table. */
277 if (ehdr->e_type != ET_REL)
278 break;
279 }
280}