blob: bcf9344bd4fb25fd6a6481c9b3e8b369a3ca1e7a [file] [log] [blame]
Ulrich Drepperce0bdb62007-02-05 07:13:52 +00001/* Functions to handle creation of Linux archives.
Roland McGrath85924782012-01-20 11:40:59 -08002 Copyright (C) 2007-2012 Red Hat, Inc.
Ulrich Drepperce0bdb62007-02-05 07:13:52 +00003 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
Ulrich Drepper0fe63532007-02-05 21:05:51 +000043/* The one symbol table we hanble. */
44struct arlib_symtab symtab;
45
46
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000047/* Initialize ARLIB_SYMTAB structure. */
48void
Ulrich Drepper0fe63532007-02-05 21:05:51 +000049arlib_init (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000050{
51#define obstack_chunk_alloc xmalloc
52#define obstack_chunk_free free
Ulrich Drepper0fe63532007-02-05 21:05:51 +000053 obstack_init (&symtab.symsoffob);
54 obstack_init (&symtab.symsnameob);
55 obstack_init (&symtab.longnamesob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000056
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,
Marek Polaceked526182011-04-15 11:41:32 +020064 since all the fields are consecutive and we fill them in
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000065 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),
Roland McGrath85924782012-01-20 11:40:59 -080072 (arlib_deterministic_output ? 0
73 : (long long int) time (NULL))));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000074 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. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +000086 obstack_grow (&symtab.symsoffob, &ar_hdr, sizeof (ar_hdr));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000087
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));
Ulrich Drepper0fe63532007-02-05 21:05:51 +000092 obstack_int_grow (&symtab.symsoffob, 0);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000093
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. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000103 obstack_grow (&symtab.longnamesob, &ar_hdr, sizeof (ar_hdr));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000104
105 /* All other members are zero. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000106 symtab.symsofflen = 0;
107 symtab.symsoff = NULL;
108 symtab.symsnamelen = 0;
109 symtab.symsname = NULL;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000110}
111
112
113/* Finalize ARLIB_SYMTAB content. */
114void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000115arlib_finalize (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000116{
117 char tmpbuf[sizeof (((struct ar_hdr *) NULL)->ar_size) + 1];
118
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000119 symtab.longnameslen = obstack_object_size (&symtab.longnamesob);
120 if (symtab.longnameslen != sizeof (struct ar_hdr))
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000121 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000122 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
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000129 symtab.longnames = obstack_finish (&symtab.longnamesob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000130
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000131 memcpy (&((struct ar_hdr *) symtab.longnames)->ar_size, tmpbuf,
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000132 snprintf (tmpbuf, sizeof (tmpbuf), "%-*zu",
133 (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000134 symtab.longnameslen - sizeof (struct ar_hdr)));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000135 }
136
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000137 symtab.symsofflen = obstack_object_size (&symtab.symsoffob);
138 assert (symtab.symsofflen % sizeof (uint32_t) == 0);
139 if (symtab.symsofflen != 0)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000140 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000141 symtab.symsoff = (uint32_t *) obstack_finish (&symtab.symsoffob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000142
143 /* Fill in the number of offsets now. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000144 symtab.symsoff[AR_HDR_WORDS] = le_bswap_32 ((symtab.symsofflen
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000145 - sizeof (struct ar_hdr))
146 / sizeof (uint32_t) - 1);
147 }
148
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000149 symtab.symsnamelen = obstack_object_size (&symtab.symsnameob);
150 if ((symtab.symsnamelen & 1) != 0)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000151 {
152 /* Add one more NUL byte to make length even. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000153 obstack_grow (&symtab.symsnameob, "", 1);
154 ++symtab.symsnamelen;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000155 }
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000156 symtab.symsname = obstack_finish (&symtab.symsnameob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000157
158 /* Determine correction for the offsets in the symbol table. */
159 off_t disp = 0;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000160 if (symtab.symsnamelen > 0)
161 disp = symtab.symsofflen + symtab.symsnamelen;
162 if (symtab.longnameslen > sizeof (struct ar_hdr))
163 disp += symtab.longnameslen;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000164
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000165 if (disp != 0 && symtab.symsoff != NULL)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000166 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000167 uint32_t nsyms = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS]);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000168
169 for (uint32_t cnt = 1; cnt <= nsyms; ++cnt)
170 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000171 uint32_t val = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS + cnt]);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000172 val += disp;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000173 symtab.symsoff[AR_HDR_WORDS + cnt] = le_bswap_32 (val);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000174 }
175 }
176
177 /* See comment for ar_date above. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000178 memcpy (&((struct ar_hdr *) symtab.symsoff)->ar_size, tmpbuf,
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000179 snprintf (tmpbuf, sizeof (tmpbuf), "%-*zu",
180 (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000181 symtab.symsofflen + symtab.symsnamelen
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000182 - sizeof (struct ar_hdr)));
183}
184
185
186/* Free resources for ARLIB_SYMTAB. */
187void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000188arlib_fini (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000189{
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000190 obstack_free (&symtab.symsoffob, NULL);
191 obstack_free (&symtab.symsnameob, NULL);
192 obstack_free (&symtab.longnamesob, NULL);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000193}
194
195
196/* Add name a file offset of a symbol. */
197void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000198arlib_add_symref (const char *symname, off_t symoff)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000199{
200 /* For all supported platforms the following is true. */
201 assert (sizeof (uint32_t) == sizeof (int));
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000202 obstack_int_grow (&symtab.symsoffob, (int) le_bswap_32 (symoff));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000203
204 size_t symname_len = strlen (symname) + 1;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000205 obstack_grow (&symtab.symsnameob, symname, symname_len);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000206}
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,
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000212 off_t off)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000213{
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)
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}