blob: 1b8785e469ab0ae615b165a5486c324b37422d56 [file] [log] [blame]
Ulrich Drepperce0bdb62007-02-05 07:13:52 +00001/* Functions to handle creation of Linux archives.
2 Copyright (C) 2007 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
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,
64 since all the fields are consecutive and we fill them in 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 (long long int) time (NULL)));
73 assert ((sizeof (struct ar_hdr) % sizeof (uint32_t)) == 0);
74
75 /* Note the string for the ar_uid and ar_gid cases is longer than
76 necessary. This does not matter since we copy only as much as
77 necessary but it helps the compiler to use the same string for
78 the ar_mode case. */
79 memcpy (ar_hdr.ar_uid, "0 ", sizeof (ar_hdr.ar_uid));
80 memcpy (ar_hdr.ar_gid, "0 ", sizeof (ar_hdr.ar_gid));
81 memcpy (ar_hdr.ar_mode, "0 ", sizeof (ar_hdr.ar_mode));
82 memcpy (ar_hdr.ar_fmag, ARFMAG, sizeof (ar_hdr.ar_fmag));
83
84 /* Add the archive header to the file content. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +000085 obstack_grow (&symtab.symsoffob, &ar_hdr, sizeof (ar_hdr));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000086
87 /* The first word in the offset table specifies the size. Create
88 such an entry now. The real value will be filled-in later. For
89 all supported platforms the following is true. */
90 assert (sizeof (uint32_t) == sizeof (int));
Ulrich Drepper0fe63532007-02-05 21:05:51 +000091 obstack_int_grow (&symtab.symsoffob, 0);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +000092
93 /* The long name obstack also gets its archive header. As above,
94 some of the input strings are longer than required but we only
95 copy the necessary part. */
96 memcpy (ar_hdr.ar_name, "// ", sizeof (ar_hdr.ar_name));
97 memcpy (ar_hdr.ar_date, " ", sizeof (ar_hdr.ar_date));
98 memcpy (ar_hdr.ar_uid, " ", sizeof (ar_hdr.ar_uid));
99 memcpy (ar_hdr.ar_gid, " ", sizeof (ar_hdr.ar_gid));
100 memcpy (ar_hdr.ar_mode, " ", sizeof (ar_hdr.ar_mode));
101 /* The ar_size field will be filled in later and ar_fmag is already OK. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000102 obstack_grow (&symtab.longnamesob, &ar_hdr, sizeof (ar_hdr));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000103
104 /* All other members are zero. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000105 symtab.symsofflen = 0;
106 symtab.symsoff = NULL;
107 symtab.symsnamelen = 0;
108 symtab.symsname = NULL;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000109}
110
111
112/* Finalize ARLIB_SYMTAB content. */
113void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000114arlib_finalize (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000115{
116 char tmpbuf[sizeof (((struct ar_hdr *) NULL)->ar_size) + 1];
117
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000118 symtab.longnameslen = obstack_object_size (&symtab.longnamesob);
119 if (symtab.longnameslen != sizeof (struct ar_hdr))
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000120 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000121 symtab.longnames = obstack_finish (&symtab.longnamesob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000122
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000123 memcpy (&((struct ar_hdr *) symtab.longnames)->ar_size, tmpbuf,
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000124 snprintf (tmpbuf, sizeof (tmpbuf), "%-*zu",
125 (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000126 symtab.longnameslen - sizeof (struct ar_hdr)));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000127 }
128
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000129 symtab.symsofflen = obstack_object_size (&symtab.symsoffob);
130 assert (symtab.symsofflen % sizeof (uint32_t) == 0);
131 if (symtab.symsofflen != 0)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000132 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000133 symtab.symsoff = (uint32_t *) obstack_finish (&symtab.symsoffob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000134
135 /* Fill in the number of offsets now. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000136 symtab.symsoff[AR_HDR_WORDS] = le_bswap_32 ((symtab.symsofflen
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000137 - sizeof (struct ar_hdr))
138 / sizeof (uint32_t) - 1);
139 }
140
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000141 symtab.symsnamelen = obstack_object_size (&symtab.symsnameob);
142 if ((symtab.symsnamelen & 1) != 0)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000143 {
144 /* Add one more NUL byte to make length even. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000145 obstack_grow (&symtab.symsnameob, "", 1);
146 ++symtab.symsnamelen;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000147 }
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000148 symtab.symsname = obstack_finish (&symtab.symsnameob);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000149
150 /* Determine correction for the offsets in the symbol table. */
151 off_t disp = 0;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000152 if (symtab.symsnamelen > 0)
153 disp = symtab.symsofflen + symtab.symsnamelen;
154 if (symtab.longnameslen > sizeof (struct ar_hdr))
155 disp += symtab.longnameslen;
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000156
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000157 if (disp != 0 && symtab.symsoff != NULL)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000158 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000159 uint32_t nsyms = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS]);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000160
161 for (uint32_t cnt = 1; cnt <= nsyms; ++cnt)
162 {
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000163 uint32_t val = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS + cnt]);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000164 val += disp;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000165 symtab.symsoff[AR_HDR_WORDS + cnt] = le_bswap_32 (val);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000166 }
167 }
168
169 /* See comment for ar_date above. */
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000170 memcpy (&((struct ar_hdr *) symtab.symsoff)->ar_size, tmpbuf,
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000171 snprintf (tmpbuf, sizeof (tmpbuf), "%-*zu",
172 (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000173 symtab.symsofflen + symtab.symsnamelen
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000174 - sizeof (struct ar_hdr)));
175}
176
177
178/* Free resources for ARLIB_SYMTAB. */
179void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000180arlib_fini (void)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000181{
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000182 obstack_free (&symtab.symsoffob, NULL);
183 obstack_free (&symtab.symsnameob, NULL);
184 obstack_free (&symtab.longnamesob, NULL);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000185}
186
187
188/* Add name a file offset of a symbol. */
189void
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000190arlib_add_symref (const char *symname, off_t symoff)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000191{
192 /* For all supported platforms the following is true. */
193 assert (sizeof (uint32_t) == sizeof (int));
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000194 obstack_int_grow (&symtab.symsoffob, (int) le_bswap_32 (symoff));
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000195
196 size_t symname_len = strlen (symname) + 1;
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000197 obstack_grow (&symtab.symsnameob, symname, symname_len);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000198}
199
200
201/* Add symbols from ELF with value OFFSET to the symbol table SYMTAB. */
202void
203arlib_add_symbols (Elf *elf, const char *arfname, const char *membername,
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000204 off_t off)
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000205{
206 if (sizeof (off) > sizeof (uint32_t) && off > ~((uint32_t) 0))
207 /* The archive is too big. */
208 error (EXIT_FAILURE, 0, gettext ("the archive '%s' is too large"),
209 arfname);
210
211 /* We only add symbol tables for ELF files. It makes not much sense
212 to add symbols from executables but we do so for compatibility.
213 For DSOs and executables we use the dynamic symbol table, for
214 relocatable files all the DT_SYMTAB tables. */
215 if (elf_kind (elf) != ELF_K_ELF)
216 return;
217
218 GElf_Ehdr ehdr_mem;
219 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
220 if (ehdr == NULL)
221 error (EXIT_FAILURE, 0, gettext ("cannot read ELF header of %s(%s): %s"),
222 arfname, membername, elf_errmsg (-1));
223
224 GElf_Word symtype;
225 if (ehdr->e_type == ET_REL)
226 symtype = SHT_SYMTAB;
227 else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)
228 symtype = SHT_DYNSYM;
229 else
230 /* We do not handle that type. */
231 return;
232
233 /* Iterate over all sections. */
234 Elf_Scn *scn = NULL;
235 while ((scn = elf_nextscn (elf, scn)) != NULL)
236 {
237 /* Get the section header. */
238 GElf_Shdr shdr_mem;
239 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
240 if (shdr == NULL)
241 continue;
242
243 if (shdr->sh_type != symtype)
244 continue;
245
246 Elf_Data *data = elf_getdata (scn, NULL);
247 if (data == NULL)
248 continue;
249
250 int nsyms = shdr->sh_size / shdr->sh_entsize;
251 for (int ndx = shdr->sh_info; ndx < nsyms; ++ndx)
252 {
253 GElf_Sym sym_mem;
254 GElf_Sym *sym = gelf_getsym (data, ndx, &sym_mem);
255 if (sym == NULL)
256 continue;
257
258 /* Ignore undefined symbols. */
259 if (sym->st_shndx == SHN_UNDEF)
260 continue;
261
262 /* Use this symbol. */
263 const char *symname = elf_strptr (elf, shdr->sh_link, sym->st_name);
264 if (symname != NULL)
Ulrich Drepper0fe63532007-02-05 21:05:51 +0000265 arlib_add_symref (symname, off);
Ulrich Drepperce0bdb62007-02-05 07:13:52 +0000266 }
267
268 /* Only relocatable files can have more than one symbol table. */
269 if (ehdr->e_type != ET_REL)
270 break;
271 }
272}