blob: 6811ad1f12ebaa60991b0cf1da803140563cad3f [file] [log] [blame]
The Android Open Source Project593c3652008-10-21 07:00:00 -07001/* Update data structures for changes.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 2.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <assert.h>
23//#include <endian.h>
24#include <libelf.h>
25#include <stdbool.h>
26#include <string.h>
27#include <sys/param.h>
28
29#include "libelfP.h"
30#include "elf-knowledge.h"
31
32#ifndef LIBELFBITS
33# define LIBELFBITS 32
34#endif
35
36
37
38static int
39ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
40 size_t shnum, int *change_bop)
41{
42 /* Always write the magic bytes. */
43 if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
44 {
45 memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
46 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
47 }
48
49 /* Always set the file class. */
50 update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS),
51 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
52
53 /* Set the data encoding if necessary. */
54 if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
55 {
56 ehdr->e_ident[EI_DATA] =
57 BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
58 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
59 }
60 else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM))
61 {
62 __libelf_seterrno (ELF_E_DATA_ENCODING);
63 return 1;
64 }
65 else
66 *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
67 && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
68 || (BYTE_ORDER == BIG_ENDIAN
69 && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
70
71 /* Unconditionally overwrite the ELF version. */
72 update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
73 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
74
75 if (unlikely (ehdr->e_version == EV_NONE)
76 || unlikely (ehdr->e_version >= EV_NUM))
77 {
78 __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
79 return 1;
80 }
81
82 if (unlikely (shnum >= SHN_LORESERVE))
83 {
84 update_if_changed (ehdr->e_shnum, 0,
85 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
86 }
87 else
88 update_if_changed (ehdr->e_shnum, shnum,
89 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
90
91 if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
92 {
93 ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
94 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
95 }
96
97 return 0;
98}
99
100
101off_t
102internal_function_def
103__elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum)
104{
105 ElfW2(LIBELFBITS,Ehdr) *ehdr = INTUSE(elfw2(LIBELFBITS,getehdr)) (elf);
106 int changed = 0;
107 int ehdr_flags = 0;
108 off_t size;
109
110 /* Set the default values. */
111 if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
112 return -1;
113
114 /* At least the ELF header is there. */
115 size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
116
117 /* Set the program header position. */
118 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
119 {
120 /* Only executables or shared objects have a program header. */
121 if (ehdr->e_type != ET_EXEC && unlikely (ehdr->e_type != ET_DYN))
122 {
123 __libelf_seterrno (ELF_E_INVALID_PHDR);
124 return -1;
125 }
126
127 if (elf->flags & ELF_F_LAYOUT)
128 {
129 /* The user is supposed to fill out e_phoff. Use it and
130 e_phnum to determine the maximum extend. */
131 size = MAX ((size_t) size,
132 ehdr->e_phoff
133 + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum));
134 }
135 else
136 {
137 update_if_changed (ehdr->e_phoff,
138 elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
139 ehdr_flags);
140
141 /* We need no alignment here. */
142 size += elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum);
143 }
144 }
145
146 if (shnum > 0)
147 {
148 Elf_ScnList *list;
149 bool first = true;
150
151 assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
152
153 if (shnum >= SHN_LORESERVE)
154 {
155 /* We have to fill in the number of sections in the header
156 of the zeroth section. */
157 elf->state.ELFW(elf,LIBELFBITS).scns.data[0].shdr.ELFW(e,LIBELFBITS)->sh_size
158 = shnum;
159 elf->state.ELFW(elf,LIBELFBITS).scns.data[0].shdr_flags
160 |= ELF_F_DIRTY;
161 }
162
163
164 /* Go over all sections and find out how large they are. */
165 list = &elf->state.ELFW(elf,LIBELFBITS).scns;
166
167 do
168 {
169 size_t cnt;
170
171 for (cnt = first == true; cnt < list->cnt; ++cnt)
172 {
173 Elf_Scn *scn = &list->data[cnt];
174 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
175 off_t offset = 0;
176 ElfW2(LIBELFBITS,Word) sh_entsize;
177 ElfW2(LIBELFBITS,Word) sh_align;
178
179 assert (shdr != NULL);
180 sh_entsize = shdr->sh_entsize;
181 sh_align = shdr->sh_addralign ?: 1;
182
183 /* Set the sh_entsize value if we can reliably detect it. */
184 switch (shdr->sh_type)
185 {
186 case SHT_SYMTAB:
187 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
188 break;
189 case SHT_RELA:
190 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
191 break;
192 case SHT_GROUP:
193 /* Only relocatable files can contain section groups. */
194 if (ehdr->e_type != ET_REL)
195 {
196 __libelf_seterrno (ELF_E_GROUP_NOT_REL);
197 return -1;
198 }
199 /* FALLTHROUGH */
200 case SHT_SYMTAB_SHNDX:
201 sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
202 break;
203 case SHT_HASH:
204 sh_entsize = SH_ENTSIZE_HASH (ehdr);
205 break;
206 case SHT_DYNAMIC:
207 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
208 break;
209 case SHT_REL:
210 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
211 break;
212 case SHT_DYNSYM:
213 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
214 break;
215 case SHT_SUNW_move:
216 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
217 break;
218 case SHT_SUNW_syminfo:
219 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
220 break;
221 default:
222 break;
223 }
224
225 /* If the section header contained the wrong entry size
226 correct it and mark the header as modified. */
227 update_if_changed (shdr->sh_entsize, sh_entsize,
228 scn->shdr_flags);
229
230 /* Iterate over all data blocks. */
231 if (list->data[cnt].data_list_rear != NULL)
232 {
233 Elf_Data_List *dl = &scn->data_list;
234
235 while (dl != NULL)
236 {
237 if (unlikely (dl->data.d.d_version == EV_NONE)
238 || unlikely (dl->data.d.d_version >= EV_NUM))
239 {
240 __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
241 return -1;
242 }
243
244 if (unlikely (! powerof2 (dl->data.d.d_align)))
245 {
246 __libelf_seterrno (ELF_E_INVALID_ALIGN);
247 return -1;
248 }
249
250 sh_align = MAX (sh_align, dl->data.d.d_align);
251
252 if (elf->flags & ELF_F_LAYOUT)
253 {
254 /* The user specified the offset and the size.
255 All we have to do is check whether this block
256 fits in the size specified for the section. */
257 if (unlikely ((GElf_Word) (dl->data.d.d_off
258 + dl->data.d.d_size)
259 > shdr->sh_size))
260 {
261 __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
262 return -1;
263 }
264 }
265 else
266 {
267 /* Determine the padding. */
268 offset = ((offset + dl->data.d.d_align - 1)
269 & ~(dl->data.d.d_align - 1));
270
271 update_if_changed (dl->data.d.d_off, offset,
272 changed);
273
274 offset += dl->data.d.d_size;
275 }
276
277 /* Next data block. */
278 dl = dl->next;
279 }
280 }
281
282 if (elf->flags & ELF_F_LAYOUT)
283 {
284 size = MAX ((GElf_Word) size,
285 shdr->sh_offset
286 + (shdr->sh_type != SHT_NOBITS
287 ? shdr->sh_size : 0));
288
289 /* The alignment must be a power of two. This is a
290 requirement from the ELF specification. Additionally
291 we test for the alignment of the section being large
292 enough for the largest alignment required by a data
293 block. */
294 if (unlikely (! powerof2 (shdr->sh_addralign))
295 || unlikely (shdr->sh_addralign < sh_align))
296 {
297 __libelf_seterrno (ELF_E_INVALID_ALIGN);
298 return -1;
299 }
300 }
301 else
302 {
303 /* How much alignment do we need for this section. */
304 update_if_changed (shdr->sh_addralign, sh_align,
305 scn->shdr_flags);
306
307 size = (size + sh_align - 1) & ~(sh_align - 1);
308 update_if_changed (shdr->sh_offset, (GElf_Word) size,
309 changed);
310
311 /* See whether the section size is correct. */
312 update_if_changed (shdr->sh_size, (GElf_Word) offset,
313 changed);
314
315 if (shdr->sh_type != SHT_NOBITS)
316 size += offset;
317
318 scn->flags |= changed;
319 }
320
321 /* Check that the section size is actually a multiple of
322 the entry size. */
323 if (shdr->sh_entsize != 0
324 && unlikely (shdr->sh_size % shdr->sh_entsize != 0)
325 && (elf->flags & ELF_F_PERMISSIVE) == 0)
326 {
327 __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
328 return -1;
329 }
330 }
331
332 assert (list->next == NULL || list->cnt == list->max);
333
334 first = false;
335 }
336 while ((list = list->next) != NULL);
337
338 /* Store section information. */
339 if (elf->flags & ELF_F_LAYOUT)
340 {
341 /* The user is supposed to fill out e_phoff. Use it and
342 e_phnum to determine the maximum extend. */
343 size = MAX ((GElf_Word) size,
344 (ehdr->e_shoff
345 + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
346 }
347 else
348 {
349 /* Align for section header table.
350
351 Yes, we use `sizeof' and not `__alignof__' since we do not
352 want to be surprised by architectures with less strict
353 alignment rules. */
354#define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
355 size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
356
357 update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags);
358 update_if_changed (ehdr->e_shentsize,
359 elf_typesize (LIBELFBITS, ELF_T_SHDR, 1),
360 ehdr_flags);
361
362 /* Account for the section header size. */
363 size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
364 }
365 }
366
367 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
368
369 return size;
370}