blob: c3cf47f8469f49170c899c22ed7ec8882ae23738 [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.
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>
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
Akihiko Odaki60b2bf12016-10-11 23:06:48 +090031#include <libeu.h>
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000032
33#include "arlib.h"
34
35
Ulrich Drepper0fe63532007-02-05 21:05:51 +000036/* The one symbol table we hanble. */
37struct arlib_symtab symtab;
38
39
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000040/* Initialize ARLIB_SYMTAB structure. */
41void
Ulrich Drepper0fe63532007-02-05 21:05:51 +000042arlib_init (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000043{
44#define obstack_chunk_alloc xmalloc
45#define obstack_chunk_free free
Ulrich Drepper0fe63532007-02-05 21:05:51 +000046 obstack_init (&symtab.symsoffob);
47 obstack_init (&symtab.symsnameob);
48 obstack_init (&symtab.longnamesob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000049
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,
Marek Polaceked526182011-04-15 11:41:32 +020057 since all the fields are consecutive and we fill them in
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000058 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];
Mark Wielaard03d76f42013-11-09 16:45:22 +010062 int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*lld",
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000063 (int) sizeof (ar_hdr.ar_date),
Roland McGrath85924782012-01-20 11:40:59 -080064 (arlib_deterministic_output ? 0
Mark Wielaard03d76f42013-11-09 16:45:22 +010065 : (long long int) time (NULL)));
66 memcpy (ar_hdr.ar_date, tmpbuf, s);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000067 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. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +000079 obstack_grow (&symtab.symsoffob, &ar_hdr, sizeof (ar_hdr));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000080
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));
Ulrich Drepper0fe63532007-02-05 21:05:51 +000085 obstack_int_grow (&symtab.symsoffob, 0);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000086
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. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +000096 obstack_grow (&symtab.longnamesob, &ar_hdr, sizeof (ar_hdr));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000097
98 /* All other members are zero. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +000099 symtab.symsofflen = 0;
100 symtab.symsoff = NULL;
101 symtab.symsnamelen = 0;
102 symtab.symsname = NULL;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000103}
104
105
106/* Finalize ARLIB_SYMTAB content. */
107void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000108arlib_finalize (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000109{
110 char tmpbuf[sizeof (((struct ar_hdr *) NULL)->ar_size) + 1];
111
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000112 symtab.longnameslen = obstack_object_size (&symtab.longnamesob);
113 if (symtab.longnameslen != sizeof (struct ar_hdr))
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000114 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000115 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
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000122 symtab.longnames = obstack_finish (&symtab.longnamesob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000123
Mark Wielaard03d76f42013-11-09 16:45:22 +0100124 int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*zu",
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000125 (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
Mark Wielaard03d76f42013-11-09 16:45:22 +0100126 symtab.longnameslen - sizeof (struct ar_hdr));
127 memcpy (&((struct ar_hdr *) symtab.longnames)->ar_size, tmpbuf, s);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000128 }
129
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000130 symtab.symsofflen = obstack_object_size (&symtab.symsoffob);
131 assert (symtab.symsofflen % sizeof (uint32_t) == 0);
132 if (symtab.symsofflen != 0)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000133 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000134 symtab.symsoff = (uint32_t *) obstack_finish (&symtab.symsoffob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000135
136 /* Fill in the number of offsets now. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000137 symtab.symsoff[AR_HDR_WORDS] = le_bswap_32 ((symtab.symsofflen
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000138 - sizeof (struct ar_hdr))
139 / sizeof (uint32_t) - 1);
140 }
141
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000142 symtab.symsnamelen = obstack_object_size (&symtab.symsnameob);
143 if ((symtab.symsnamelen & 1) != 0)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000144 {
145 /* Add one more NUL byte to make length even. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000146 obstack_grow (&symtab.symsnameob, "", 1);
147 ++symtab.symsnamelen;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000148 }
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000149 symtab.symsname = obstack_finish (&symtab.symsnameob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000150
151 /* Determine correction for the offsets in the symbol table. */
152 off_t disp = 0;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000153 if (symtab.symsnamelen > 0)
154 disp = symtab.symsofflen + symtab.symsnamelen;
155 if (symtab.longnameslen > sizeof (struct ar_hdr))
156 disp += symtab.longnameslen;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000157
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000158 if (disp != 0 && symtab.symsoff != NULL)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000159 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000160 uint32_t nsyms = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS]);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000161
162 for (uint32_t cnt = 1; cnt <= nsyms; ++cnt)
163 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000164 uint32_t val = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS + cnt]);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000165 val += disp;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000166 symtab.symsoff[AR_HDR_WORDS + cnt] = le_bswap_32 (val);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000167 }
168 }
169
170 /* See comment for ar_date above. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000171 memcpy (&((struct ar_hdr *) symtab.symsoff)->ar_size, tmpbuf,
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000172 snprintf (tmpbuf, sizeof (tmpbuf), "%-*zu",
173 (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000174 symtab.symsofflen + symtab.symsnamelen
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000175 - sizeof (struct ar_hdr)));
176}
177
178
179/* Free resources for ARLIB_SYMTAB. */
180void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000181arlib_fini (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000182{
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000183 obstack_free (&symtab.symsoffob, NULL);
184 obstack_free (&symtab.symsnameob, NULL);
185 obstack_free (&symtab.longnamesob, NULL);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000186}
187
188
189/* Add name a file offset of a symbol. */
190void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000191arlib_add_symref (const char *symname, off_t symoff)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000192{
193 /* For all supported platforms the following is true. */
194 assert (sizeof (uint32_t) == sizeof (int));
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000195 obstack_int_grow (&symtab.symsoffob, (int) le_bswap_32 (symoff));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000196
197 size_t symname_len = strlen (symname) + 1;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000198 obstack_grow (&symtab.symsnameob, symname, symname_len);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000199}
200
201
202/* Add symbols from ELF with value OFFSET to the symbol table SYMTAB. */
203void
204arlib_add_symbols (Elf *elf, const char *arfname, const char *membername,
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000205 off_t off)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000206{
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)
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000266 arlib_add_symref (symname, off);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000267 }
268
269 /* Only relocatable files can have more than one symbol table. */
270 if (ehdr->e_type != ET_REL)
271 break;
272 }
273}