Rev 5191 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5191 | serge | 1 | /* simple-object-elf.c -- routines to manipulate ELF object files. |
2 | Copyright 2010 Free Software Foundation, Inc. |
||
3 | Written by Ian Lance Taylor, Google. |
||
4 | |||
5 | This program is free software; you can redistribute it and/or modify it |
||
6 | under the terms of the GNU General Public License as published by the |
||
7 | Free Software Foundation; either version 2, or (at your option) any |
||
8 | later version. |
||
9 | |||
10 | This program is distributed in the hope that it will be useful, |
||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
13 | GNU General Public License for more details. |
||
14 | |||
15 | You should have received a copy of the GNU General Public License |
||
16 | along with this program; if not, write to the Free Software |
||
17 | Foundation, 51 Franklin Street - Fifth Floor, |
||
18 | Boston, MA 02110-1301, USA. */ |
||
19 | |||
20 | #include "config.h" |
||
21 | #include "libiberty.h" |
||
22 | #include "simple-object.h" |
||
23 | |||
24 | #include |
||
25 | #include |
||
26 | |||
27 | #ifdef HAVE_STDLIB_H |
||
28 | #include |
||
29 | #endif |
||
30 | |||
31 | #ifdef HAVE_STDINT_H |
||
32 | #include |
||
33 | #endif |
||
34 | |||
35 | #ifdef HAVE_STRING_H |
||
36 | #include |
||
37 | #endif |
||
38 | |||
39 | #ifdef HAVE_INTTYPES_H |
||
40 | #include |
||
41 | #endif |
||
42 | |||
43 | #include "simple-object-common.h" |
||
44 | |||
45 | /* ELF structures and constants. */ |
||
46 | |||
47 | /* 32-bit ELF file header. */ |
||
48 | |||
49 | typedef struct { |
||
50 | unsigned char e_ident[16]; /* ELF "magic number" */ |
||
51 | unsigned char e_type[2]; /* Identifies object file type */ |
||
52 | unsigned char e_machine[2]; /* Specifies required architecture */ |
||
53 | unsigned char e_version[4]; /* Identifies object file version */ |
||
54 | unsigned char e_entry[4]; /* Entry point virtual address */ |
||
55 | unsigned char e_phoff[4]; /* Program header table file offset */ |
||
56 | unsigned char e_shoff[4]; /* Section header table file offset */ |
||
57 | unsigned char e_flags[4]; /* Processor-specific flags */ |
||
58 | unsigned char e_ehsize[2]; /* ELF header size in bytes */ |
||
59 | unsigned char e_phentsize[2]; /* Program header table entry size */ |
||
60 | unsigned char e_phnum[2]; /* Program header table entry count */ |
||
61 | unsigned char e_shentsize[2]; /* Section header table entry size */ |
||
62 | unsigned char e_shnum[2]; /* Section header table entry count */ |
||
63 | unsigned char e_shstrndx[2]; /* Section header string table index */ |
||
64 | } Elf32_External_Ehdr; |
||
65 | |||
66 | /* 64-bit ELF file header. */ |
||
67 | |||
68 | typedef struct { |
||
69 | unsigned char e_ident[16]; /* ELF "magic number" */ |
||
70 | unsigned char e_type[2]; /* Identifies object file type */ |
||
71 | unsigned char e_machine[2]; /* Specifies required architecture */ |
||
72 | unsigned char e_version[4]; /* Identifies object file version */ |
||
73 | unsigned char e_entry[8]; /* Entry point virtual address */ |
||
74 | unsigned char e_phoff[8]; /* Program header table file offset */ |
||
75 | unsigned char e_shoff[8]; /* Section header table file offset */ |
||
76 | unsigned char e_flags[4]; /* Processor-specific flags */ |
||
77 | unsigned char e_ehsize[2]; /* ELF header size in bytes */ |
||
78 | unsigned char e_phentsize[2]; /* Program header table entry size */ |
||
79 | unsigned char e_phnum[2]; /* Program header table entry count */ |
||
80 | unsigned char e_shentsize[2]; /* Section header table entry size */ |
||
81 | unsigned char e_shnum[2]; /* Section header table entry count */ |
||
82 | unsigned char e_shstrndx[2]; /* Section header string table index */ |
||
83 | } Elf64_External_Ehdr; |
||
84 | |||
85 | /* Indexes and values in e_ident field of Ehdr. */ |
||
86 | |||
87 | #define EI_MAG0 0 /* File identification byte 0 index */ |
||
88 | #define ELFMAG0 0x7F /* Magic number byte 0 */ |
||
89 | |||
90 | #define EI_MAG1 1 /* File identification byte 1 index */ |
||
91 | #define ELFMAG1 'E' /* Magic number byte 1 */ |
||
92 | |||
93 | #define EI_MAG2 2 /* File identification byte 2 index */ |
||
94 | #define ELFMAG2 'L' /* Magic number byte 2 */ |
||
95 | |||
96 | #define EI_MAG3 3 /* File identification byte 3 index */ |
||
97 | #define ELFMAG3 'F' /* Magic number byte 3 */ |
||
98 | |||
99 | #define EI_CLASS 4 /* File class */ |
||
100 | #define ELFCLASSNONE 0 /* Invalid class */ |
||
101 | #define ELFCLASS32 1 /* 32-bit objects */ |
||
102 | #define ELFCLASS64 2 /* 64-bit objects */ |
||
103 | |||
104 | #define EI_DATA 5 /* Data encoding */ |
||
105 | #define ELFDATANONE 0 /* Invalid data encoding */ |
||
106 | #define ELFDATA2LSB 1 /* 2's complement, little endian */ |
||
107 | #define ELFDATA2MSB 2 /* 2's complement, big endian */ |
||
108 | |||
109 | #define EI_VERSION 6 /* File version */ |
||
110 | #define EV_CURRENT 1 /* Current version */ |
||
111 | |||
112 | #define EI_OSABI 7 /* Operating System/ABI indication */ |
||
113 | |||
114 | /* Values for e_type field of Ehdr. */ |
||
115 | |||
116 | #define ET_REL 1 /* Relocatable file */ |
||
117 | |||
118 | /* Values for e_machine field of Ehdr. */ |
||
119 | |||
120 | #define EM_SPARC 2 /* SUN SPARC */ |
||
121 | #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ |
||
122 | |||
123 | /* Special section index values. */ |
||
124 | |||
125 | #define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ |
||
126 | #define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ |
||
127 | |||
128 | /* 32-bit ELF program header. */ |
||
129 | |||
130 | typedef struct { |
||
131 | unsigned char p_type[4]; /* Identifies program segment type */ |
||
132 | unsigned char p_offset[4]; /* Segment file offset */ |
||
133 | unsigned char p_vaddr[4]; /* Segment virtual address */ |
||
134 | unsigned char p_paddr[4]; /* Segment physical address */ |
||
135 | unsigned char p_filesz[4]; /* Segment size in file */ |
||
136 | unsigned char p_memsz[4]; /* Segment size in memory */ |
||
137 | unsigned char p_flags[4]; /* Segment flags */ |
||
138 | unsigned char p_align[4]; /* Segment alignment, file & memory */ |
||
139 | } Elf32_External_Phdr; |
||
140 | |||
141 | /* 64-bit ELF program header. */ |
||
142 | |||
143 | typedef struct { |
||
144 | unsigned char p_type[4]; /* Identifies program segment type */ |
||
145 | unsigned char p_flags[4]; /* Segment flags */ |
||
146 | unsigned char p_offset[8]; /* Segment file offset */ |
||
147 | unsigned char p_vaddr[8]; /* Segment virtual address */ |
||
148 | unsigned char p_paddr[8]; /* Segment physical address */ |
||
149 | unsigned char p_filesz[8]; /* Segment size in file */ |
||
150 | unsigned char p_memsz[8]; /* Segment size in memory */ |
||
151 | unsigned char p_align[8]; /* Segment alignment, file & memory */ |
||
152 | } Elf64_External_Phdr; |
||
153 | |||
154 | /* 32-bit ELF section header */ |
||
155 | |||
156 | typedef struct { |
||
157 | unsigned char sh_name[4]; /* Section name, index in string tbl */ |
||
158 | unsigned char sh_type[4]; /* Type of section */ |
||
159 | unsigned char sh_flags[4]; /* Miscellaneous section attributes */ |
||
160 | unsigned char sh_addr[4]; /* Section virtual addr at execution */ |
||
161 | unsigned char sh_offset[4]; /* Section file offset */ |
||
162 | unsigned char sh_size[4]; /* Size of section in bytes */ |
||
163 | unsigned char sh_link[4]; /* Index of another section */ |
||
164 | unsigned char sh_info[4]; /* Additional section information */ |
||
165 | unsigned char sh_addralign[4]; /* Section alignment */ |
||
166 | unsigned char sh_entsize[4]; /* Entry size if section holds table */ |
||
167 | } Elf32_External_Shdr; |
||
168 | |||
169 | /* 64-bit ELF section header. */ |
||
170 | |||
171 | typedef struct { |
||
172 | unsigned char sh_name[4]; /* Section name, index in string tbl */ |
||
173 | unsigned char sh_type[4]; /* Type of section */ |
||
174 | unsigned char sh_flags[8]; /* Miscellaneous section attributes */ |
||
175 | unsigned char sh_addr[8]; /* Section virtual addr at execution */ |
||
176 | unsigned char sh_offset[8]; /* Section file offset */ |
||
177 | unsigned char sh_size[8]; /* Size of section in bytes */ |
||
178 | unsigned char sh_link[4]; /* Index of another section */ |
||
179 | unsigned char sh_info[4]; /* Additional section information */ |
||
180 | unsigned char sh_addralign[8]; /* Section alignment */ |
||
181 | unsigned char sh_entsize[8]; /* Entry size if section holds table */ |
||
182 | } Elf64_External_Shdr; |
||
183 | |||
184 | /* Values for sh_type field. */ |
||
185 | |||
186 | #define SHT_PROGBITS 1 /* Program data */ |
||
187 | #define SHT_STRTAB 3 /* A string table */ |
||
188 | |||
189 | /* Functions to fetch and store different ELF types, depending on the |
||
190 | endianness and size. */ |
||
191 | |||
192 | struct elf_type_functions |
||
193 | { |
||
194 | unsigned short (*fetch_Elf_Half) (const unsigned char *); |
||
195 | unsigned int (*fetch_Elf_Word) (const unsigned char *); |
||
196 | ulong_type (*fetch_Elf_Addr) (const unsigned char *); |
||
197 | void (*set_Elf_Half) (unsigned char *, unsigned short); |
||
198 | void (*set_Elf_Word) (unsigned char *, unsigned int); |
||
199 | void (*set_Elf_Addr) (unsigned char *, ulong_type); |
||
200 | }; |
||
201 | |||
202 | static const struct elf_type_functions elf_big_32_functions = |
||
203 | { |
||
204 | simple_object_fetch_big_16, |
||
205 | simple_object_fetch_big_32, |
||
206 | simple_object_fetch_big_32_ulong, |
||
207 | simple_object_set_big_16, |
||
208 | simple_object_set_big_32, |
||
209 | simple_object_set_big_32_ulong |
||
210 | }; |
||
211 | |||
212 | static const struct elf_type_functions elf_little_32_functions = |
||
213 | { |
||
214 | simple_object_fetch_little_16, |
||
215 | simple_object_fetch_little_32, |
||
216 | simple_object_fetch_little_32_ulong, |
||
217 | simple_object_set_little_16, |
||
218 | simple_object_set_little_32, |
||
219 | simple_object_set_little_32_ulong |
||
220 | }; |
||
221 | |||
222 | #ifdef UNSIGNED_64BIT_TYPE |
||
223 | |||
224 | static const struct elf_type_functions elf_big_64_functions = |
||
225 | { |
||
226 | simple_object_fetch_big_16, |
||
227 | simple_object_fetch_big_32, |
||
228 | simple_object_fetch_big_64, |
||
229 | simple_object_set_big_16, |
||
230 | simple_object_set_big_32, |
||
231 | simple_object_set_big_64 |
||
232 | }; |
||
233 | |||
234 | static const struct elf_type_functions elf_little_64_functions = |
||
235 | { |
||
236 | simple_object_fetch_little_16, |
||
237 | simple_object_fetch_little_32, |
||
238 | simple_object_fetch_little_64, |
||
239 | simple_object_set_little_16, |
||
240 | simple_object_set_little_32, |
||
241 | simple_object_set_little_64 |
||
242 | }; |
||
243 | |||
244 | #endif |
||
245 | |||
246 | /* Hideous macro to fetch the value of a field from an external ELF |
||
247 | struct of some sort. TYPEFUNCS is the set of type functions. |
||
248 | BUFFER points to the external data. STRUCTTYPE is the appropriate |
||
249 | struct type. FIELD is a field within the struct. TYPE is the type |
||
250 | of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr. */ |
||
251 | |||
252 | #define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \ |
||
253 | ((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD))) |
||
254 | |||
255 | /* Even more hideous macro to fetch the value of FIELD from BUFFER. |
||
256 | SIZE is 32 or 64. STRUCTTYPE is the name of the struct from |
||
257 | elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in |
||
258 | the struct. TYPE is the type of the field in the struct: Elf_Half, |
||
259 | Elf_Word, or Elf_Addr. */ |
||
260 | |||
261 | #define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, \ |
||
262 | FIELD, TYPE) \ |
||
263 | ELF_FETCH_STRUCT_FIELD (TYPEFUNCS, \ |
||
264 | Elf ## SIZE ## _External_ ## STRUCTTYPE, \ |
||
265 | FIELD, BUFFER, TYPE) |
||
266 | |||
267 | /* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value. */ |
||
268 | |||
269 | #define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, \ |
||
270 | FIELD, TYPE) \ |
||
271 | ((CLASS) == ELFCLASS32 \ |
||
272 | ? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \ |
||
273 | TYPE) \ |
||
274 | : ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \ |
||
275 | TYPE)) |
||
276 | |||
277 | /* Hideous macro to set the value of a field in an external ELF |
||
278 | structure to VAL. TYPEFUNCS is the set of type functions. BUFFER |
||
279 | points to the external data. STRUCTTYPE is the appropriate |
||
280 | structure type. FIELD is a field within the struct. TYPE is the |
||
281 | type of the field in the struct: Elf_Half, Elf_Word, or |
||
282 | Elf_Addr. */ |
||
283 | |||
284 | #define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \ |
||
285 | (TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL)) |
||
286 | |||
287 | /* Even more hideous macro to set the value of FIELD in BUFFER to VAL. |
||
288 | SIZE is 32 or 64. STRUCTTYPE is the name of the struct from |
||
289 | elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in |
||
290 | the struct. TYPE is the type of the field in the struct: Elf_Half, |
||
291 | Elf_Word, or Elf_Addr. */ |
||
292 | |||
293 | #define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \ |
||
294 | TYPE, VAL) \ |
||
295 | ELF_SET_STRUCT_FIELD (TYPEFUNCS, \ |
||
296 | Elf ## SIZE ## _External_ ## STRUCTTYPE, \ |
||
297 | FIELD, BUFFER, TYPE, VAL) |
||
298 | |||
299 | /* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value. */ |
||
300 | |||
301 | #define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD, \ |
||
302 | TYPE, VAL) \ |
||
303 | ((CLASS) == ELFCLASS32 \ |
||
304 | ? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \ |
||
305 | TYPE, VAL) \ |
||
306 | : ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \ |
||
307 | TYPE, VAL)) |
||
308 | |||
309 | /* Private data for an simple_object_read. */ |
||
310 | |||
311 | struct simple_object_elf_read |
||
312 | { |
||
313 | /* Type functions. */ |
||
314 | const struct elf_type_functions* type_functions; |
||
315 | /* Elf data. */ |
||
316 | unsigned char ei_data; |
||
317 | /* Elf class. */ |
||
318 | unsigned char ei_class; |
||
319 | /* ELF OS ABI. */ |
||
320 | unsigned char ei_osabi; |
||
321 | /* Elf machine number. */ |
||
322 | unsigned short machine; |
||
323 | /* Processor specific flags. */ |
||
324 | unsigned int flags; |
||
325 | /* File offset of section headers. */ |
||
326 | ulong_type shoff; |
||
327 | /* Number of sections. */ |
||
328 | unsigned int shnum; |
||
329 | /* Index of string table section header. */ |
||
330 | unsigned int shstrndx; |
||
331 | }; |
||
332 | |||
333 | /* Private data for an simple_object_attributes. */ |
||
334 | |||
335 | struct simple_object_elf_attributes |
||
336 | { |
||
337 | /* Type functions. */ |
||
338 | const struct elf_type_functions* type_functions; |
||
339 | /* Elf data. */ |
||
340 | unsigned char ei_data; |
||
341 | /* Elf class. */ |
||
342 | unsigned char ei_class; |
||
343 | /* ELF OS ABI. */ |
||
344 | unsigned char ei_osabi; |
||
345 | /* Elf machine number. */ |
||
346 | unsigned short machine; |
||
347 | /* Processor specific flags. */ |
||
348 | unsigned int flags; |
||
349 | }; |
||
350 | |||
351 | /* See if we have an ELF file. */ |
||
352 | |||
353 | static void * |
||
354 | simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], |
||
355 | int descriptor, off_t offset, |
||
356 | const char *segment_name ATTRIBUTE_UNUSED, |
||
357 | const char **errmsg, int *err) |
||
358 | { |
||
359 | unsigned char ei_data; |
||
360 | unsigned char ei_class; |
||
361 | const struct elf_type_functions *type_functions; |
||
362 | unsigned char ehdr[sizeof (Elf64_External_Ehdr)]; |
||
363 | struct simple_object_elf_read *eor; |
||
364 | |||
365 | if (header[EI_MAG0] != ELFMAG0 |
||
366 | || header[EI_MAG1] != ELFMAG1 |
||
367 | || header[EI_MAG2] != ELFMAG2 |
||
368 | || header[EI_MAG3] != ELFMAG3 |
||
369 | || header[EI_VERSION] != EV_CURRENT) |
||
370 | { |
||
371 | *errmsg = NULL; |
||
372 | *err = 0; |
||
373 | return NULL; |
||
374 | } |
||
375 | |||
376 | ei_data = header[EI_DATA]; |
||
377 | if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB) |
||
378 | { |
||
379 | *errmsg = "unknown ELF endianness"; |
||
380 | *err = 0; |
||
381 | return NULL; |
||
382 | } |
||
383 | |||
384 | ei_class = header[EI_CLASS]; |
||
385 | switch (ei_class) |
||
386 | { |
||
387 | case ELFCLASS32: |
||
388 | type_functions = (ei_data == ELFDATA2LSB |
||
389 | ? &elf_little_32_functions |
||
390 | : &elf_big_32_functions); |
||
391 | break; |
||
392 | |||
393 | case ELFCLASS64: |
||
394 | #ifndef UNSIGNED_64BIT_TYPE |
||
395 | *errmsg = "64-bit ELF objects not supported"; |
||
396 | *err = 0; |
||
397 | return NULL; |
||
398 | #else |
||
399 | type_functions = (ei_data == ELFDATA2LSB |
||
400 | ? &elf_little_64_functions |
||
401 | : &elf_big_64_functions); |
||
402 | break; |
||
403 | #endif |
||
404 | |||
405 | default: |
||
406 | *errmsg = "unrecognized ELF size"; |
||
407 | *err = 0; |
||
408 | return NULL; |
||
409 | } |
||
410 | |||
411 | if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr, |
||
412 | errmsg, err)) |
||
413 | return NULL; |
||
414 | |||
415 | eor = XNEW (struct simple_object_elf_read); |
||
416 | eor->type_functions = type_functions; |
||
417 | eor->ei_data = ei_data; |
||
418 | eor->ei_class = ei_class; |
||
419 | eor->ei_osabi = header[EI_OSABI]; |
||
420 | eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, |
||
421 | e_machine, Elf_Half); |
||
422 | eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, |
||
423 | e_flags, Elf_Word); |
||
424 | eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, |
||
425 | e_shoff, Elf_Addr); |
||
426 | eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, |
||
427 | e_shnum, Elf_Half); |
||
428 | eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, |
||
429 | e_shstrndx, Elf_Half); |
||
430 | |||
431 | if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX) |
||
432 | && eor->shoff != 0) |
||
433 | { |
||
434 | unsigned char shdr[sizeof (Elf64_External_Shdr)]; |
||
435 | |||
436 | /* Object file has more than 0xffff sections. */ |
||
437 | |||
438 | if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr, |
||
439 | (ei_class == ELFCLASS32 |
||
440 | ? sizeof (Elf32_External_Shdr) |
||
441 | : sizeof (Elf64_External_Shdr)), |
||
442 | errmsg, err)) |
||
443 | { |
||
444 | XDELETE (eor); |
||
445 | return NULL; |
||
446 | } |
||
447 | |||
448 | if (eor->shnum == 0) |
||
449 | eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
||
450 | shdr, sh_size, Elf_Addr); |
||
451 | |||
452 | if (eor->shstrndx == SHN_XINDEX) |
||
453 | { |
||
454 | eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
||
455 | shdr, sh_link, Elf_Word); |
||
456 | |||
457 | /* Versions of the GNU binutils between 2.12 and 2.18 did |
||
458 | not handle objects with more than SHN_LORESERVE sections |
||
459 | correctly. All large section indexes were offset by |
||
460 | 0x100. There is more information at |
||
461 | http://sourceware.org/bugzilla/show_bug.cgi?id-5900 . |
||
462 | Fortunately these object files are easy to detect, as the |
||
463 | GNU binutils always put the section header string table |
||
464 | near the end of the list of sections. Thus if the |
||
465 | section header string table index is larger than the |
||
466 | number of sections, then we know we have to subtract |
||
467 | 0x100 to get the real section index. */ |
||
468 | if (eor->shstrndx >= eor->shnum |
||
469 | && eor->shstrndx >= SHN_LORESERVE + 0x100) |
||
470 | eor->shstrndx -= 0x100; |
||
471 | } |
||
472 | } |
||
473 | |||
474 | if (eor->shstrndx >= eor->shnum) |
||
475 | { |
||
476 | *errmsg = "invalid ELF shstrndx >= shnum"; |
||
477 | *err = 0; |
||
478 | XDELETE (eor); |
||
479 | return NULL; |
||
480 | } |
||
481 | |||
482 | return (void *) eor; |
||
483 | } |
||
484 | |||
485 | /* Find all sections in an ELF file. */ |
||
486 | |||
487 | static const char * |
||
488 | simple_object_elf_find_sections (simple_object_read *sobj, |
||
489 | int (*pfn) (void *, const char *, |
||
490 | off_t offset, off_t length), |
||
491 | void *data, |
||
492 | int *err) |
||
493 | { |
||
494 | struct simple_object_elf_read *eor = |
||
495 | (struct simple_object_elf_read *) sobj->data; |
||
496 | const struct elf_type_functions *type_functions = eor->type_functions; |
||
497 | unsigned char ei_class = eor->ei_class; |
||
498 | size_t shdr_size; |
||
499 | unsigned int shnum; |
||
500 | unsigned char *shdrs; |
||
501 | const char *errmsg; |
||
502 | unsigned char *shstrhdr; |
||
503 | size_t name_size; |
||
504 | off_t shstroff; |
||
505 | unsigned char *names; |
||
506 | unsigned int i; |
||
507 | |||
508 | shdr_size = (ei_class == ELFCLASS32 |
||
509 | ? sizeof (Elf32_External_Shdr) |
||
510 | : sizeof (Elf64_External_Shdr)); |
||
511 | |||
512 | /* Read the section headers. We skip section 0, which is not a |
||
513 | useful section. */ |
||
514 | |||
515 | shnum = eor->shnum; |
||
516 | shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1)); |
||
517 | |||
518 | if (!simple_object_internal_read (sobj->descriptor, |
||
519 | sobj->offset + eor->shoff + shdr_size, |
||
520 | shdrs, |
||
521 | shdr_size * (shnum - 1), |
||
522 | &errmsg, err)) |
||
523 | { |
||
524 | XDELETEVEC (shdrs); |
||
525 | return errmsg; |
||
526 | } |
||
527 | |||
528 | /* Read the section names. */ |
||
529 | |||
530 | shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size; |
||
531 | name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
||
532 | shstrhdr, sh_size, Elf_Addr); |
||
533 | shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
||
534 | shstrhdr, sh_offset, Elf_Addr); |
||
535 | names = XNEWVEC (unsigned char, name_size); |
||
536 | if (!simple_object_internal_read (sobj->descriptor, |
||
537 | sobj->offset + shstroff, |
||
538 | names, name_size, &errmsg, err)) |
||
539 | { |
||
540 | XDELETEVEC (names); |
||
541 | XDELETEVEC (shdrs); |
||
542 | return errmsg; |
||
543 | } |
||
544 | |||
545 | for (i = 1; i < shnum; ++i) |
||
546 | { |
||
547 | unsigned char *shdr; |
||
548 | unsigned int sh_name; |
||
549 | const char *name; |
||
550 | off_t offset; |
||
551 | off_t length; |
||
552 | |||
553 | shdr = shdrs + (i - 1) * shdr_size; |
||
554 | sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
||
555 | shdr, sh_name, Elf_Word); |
||
556 | if (sh_name >= name_size) |
||
557 | { |
||
558 | *err = 0; |
||
559 | XDELETEVEC (names); |
||
560 | XDELETEVEC (shdrs); |
||
561 | return "ELF section name out of range"; |
||
562 | } |
||
563 | |||
564 | name = (const char *) names + sh_name; |
||
565 | offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
||
566 | shdr, sh_offset, Elf_Addr); |
||
567 | length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
||
568 | shdr, sh_size, Elf_Addr); |
||
569 | |||
570 | if (!(*pfn) (data, name, offset, length)) |
||
571 | break; |
||
572 | } |
||
573 | |||
574 | XDELETEVEC (names); |
||
575 | XDELETEVEC (shdrs); |
||
576 | |||
577 | return NULL; |
||
578 | } |
||
579 | |||
580 | /* Fetch the attributes for an simple_object_read. */ |
||
581 | |||
582 | static void * |
||
583 | simple_object_elf_fetch_attributes (simple_object_read *sobj, |
||
584 | const char **errmsg ATTRIBUTE_UNUSED, |
||
585 | int *err ATTRIBUTE_UNUSED) |
||
586 | { |
||
587 | struct simple_object_elf_read *eor = |
||
588 | (struct simple_object_elf_read *) sobj->data; |
||
589 | struct simple_object_elf_attributes *ret; |
||
590 | |||
591 | ret = XNEW (struct simple_object_elf_attributes); |
||
592 | ret->type_functions = eor->type_functions; |
||
593 | ret->ei_data = eor->ei_data; |
||
594 | ret->ei_class = eor->ei_class; |
||
595 | ret->ei_osabi = eor->ei_osabi; |
||
596 | ret->machine = eor->machine; |
||
597 | ret->flags = eor->flags; |
||
598 | return ret; |
||
599 | } |
||
600 | |||
601 | /* Release the privata data for an simple_object_read. */ |
||
602 | |||
603 | static void |
||
604 | simple_object_elf_release_read (void *data) |
||
605 | { |
||
606 | XDELETE (data); |
||
607 | } |
||
608 | |||
609 | /* Compare two attributes structures. */ |
||
610 | |||
611 | static const char * |
||
612 | simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err) |
||
613 | { |
||
614 | struct simple_object_elf_attributes *to = |
||
615 | (struct simple_object_elf_attributes *) todata; |
||
616 | struct simple_object_elf_attributes *from = |
||
617 | (struct simple_object_elf_attributes *) fromdata; |
||
618 | |||
619 | if (to->ei_data != from->ei_data || to->ei_class != from->ei_class) |
||
620 | { |
||
621 | *err = 0; |
||
622 | return "ELF object format mismatch"; |
||
623 | } |
||
624 | |||
625 | if (to->machine != from->machine) |
||
626 | { |
||
627 | int ok; |
||
628 | |||
629 | /* EM_SPARC and EM_SPARC32PLUS are compatible and force an |
||
630 | output of EM_SPARC32PLUS. */ |
||
631 | ok = 0; |
||
632 | switch (to->machine) |
||
633 | { |
||
634 | case EM_SPARC: |
||
635 | if (from->machine == EM_SPARC32PLUS) |
||
636 | { |
||
637 | to->machine = from->machine; |
||
638 | ok = 1; |
||
639 | } |
||
640 | break; |
||
641 | |||
642 | case EM_SPARC32PLUS: |
||
643 | if (from->machine == EM_SPARC) |
||
644 | ok = 1; |
||
645 | break; |
||
646 | |||
647 | default: |
||
648 | break; |
||
649 | } |
||
650 | |||
651 | if (!ok) |
||
652 | { |
||
653 | *err = 0; |
||
654 | return "ELF machine number mismatch"; |
||
655 | } |
||
656 | } |
||
657 | |||
658 | return NULL; |
||
659 | } |
||
660 | |||
661 | /* Release the private data for an attributes structure. */ |
||
662 | |||
663 | static void |
||
664 | simple_object_elf_release_attributes (void *data) |
||
665 | { |
||
666 | XDELETE (data); |
||
667 | } |
||
668 | |||
669 | /* Prepare to write out a file. */ |
||
670 | |||
671 | static void * |
||
672 | simple_object_elf_start_write (void *attributes_data, |
||
673 | const char **errmsg ATTRIBUTE_UNUSED, |
||
674 | int *err ATTRIBUTE_UNUSED) |
||
675 | { |
||
676 | struct simple_object_elf_attributes *attrs = |
||
677 | (struct simple_object_elf_attributes *) attributes_data; |
||
678 | struct simple_object_elf_attributes *ret; |
||
679 | |||
680 | /* We're just going to record the attributes, but we need to make a |
||
681 | copy because the user may delete them. */ |
||
682 | ret = XNEW (struct simple_object_elf_attributes); |
||
683 | *ret = *attrs; |
||
684 | return ret; |
||
685 | } |
||
686 | |||
687 | /* Write out an ELF ehdr. */ |
||
688 | |||
689 | static int |
||
690 | simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor, |
||
691 | const char **errmsg, int *err) |
||
692 | { |
||
693 | struct simple_object_elf_attributes *attrs = |
||
694 | (struct simple_object_elf_attributes *) sobj->data; |
||
695 | const struct elf_type_functions* fns; |
||
696 | unsigned char cl; |
||
697 | size_t ehdr_size; |
||
698 | unsigned char buf[sizeof (Elf64_External_Ehdr)]; |
||
699 | simple_object_write_section *section; |
||
700 | unsigned int shnum; |
||
6324 | serge | 701 | unsigned int shstrndx; |
5191 | serge | 702 | |
703 | fns = attrs->type_functions; |
||
704 | cl = attrs->ei_class; |
||
705 | |||
706 | shnum = 0; |
||
707 | for (section = sobj->sections; section != NULL; section = section->next) |
||
708 | ++shnum; |
||
709 | if (shnum > 0) |
||
710 | { |
||
711 | /* Add a section header for the dummy section and one for |
||
712 | .shstrtab. */ |
||
713 | shnum += 2; |
||
714 | } |
||
715 | |||
716 | ehdr_size = (cl == ELFCLASS32 |
||
717 | ? sizeof (Elf32_External_Ehdr) |
||
718 | : sizeof (Elf64_External_Ehdr)); |
||
719 | memset (buf, 0, sizeof (Elf64_External_Ehdr)); |
||
720 | |||
721 | buf[EI_MAG0] = ELFMAG0; |
||
722 | buf[EI_MAG1] = ELFMAG1; |
||
723 | buf[EI_MAG2] = ELFMAG2; |
||
724 | buf[EI_MAG3] = ELFMAG3; |
||
725 | buf[EI_CLASS] = cl; |
||
726 | buf[EI_DATA] = attrs->ei_data; |
||
727 | buf[EI_VERSION] = EV_CURRENT; |
||
728 | buf[EI_OSABI] = attrs->ei_osabi; |
||
729 | |||
730 | ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL); |
||
731 | ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine); |
||
732 | ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT); |
||
733 | /* e_entry left as zero. */ |
||
734 | /* e_phoff left as zero. */ |
||
735 | ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size); |
||
736 | ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags); |
||
737 | ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size); |
||
738 | ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half, |
||
739 | (cl == ELFCLASS32 |
||
740 | ? sizeof (Elf32_External_Phdr) |
||
741 | : sizeof (Elf64_External_Phdr))); |
||
742 | /* e_phnum left as zero. */ |
||
743 | ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half, |
||
744 | (cl == ELFCLASS32 |
||
745 | ? sizeof (Elf32_External_Shdr) |
||
746 | : sizeof (Elf64_External_Shdr))); |
||
6324 | serge | 747 | ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, |
748 | shnum >= SHN_LORESERVE ? 0 : shnum); |
||
749 | if (shnum == 0) |
||
750 | shstrndx = 0; |
||
751 | else |
||
752 | { |
||
753 | shstrndx = shnum - 1; |
||
754 | if (shstrndx >= SHN_LORESERVE) |
||
755 | shstrndx = SHN_XINDEX; |
||
756 | } |
||
757 | ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, shstrndx); |
||
5191 | serge | 758 | |
759 | return simple_object_internal_write (descriptor, 0, buf, ehdr_size, |
||
760 | errmsg, err); |
||
761 | } |
||
762 | |||
763 | /* Write out an ELF shdr. */ |
||
764 | |||
765 | static int |
||
766 | simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor, |
||
767 | off_t offset, unsigned int sh_name, |
||
768 | unsigned int sh_type, unsigned int sh_flags, |
||
769 | unsigned int sh_offset, unsigned int sh_size, |
||
6324 | serge | 770 | unsigned int sh_link, unsigned int sh_addralign, |
771 | const char **errmsg, int *err) |
||
5191 | serge | 772 | { |
773 | struct simple_object_elf_attributes *attrs = |
||
774 | (struct simple_object_elf_attributes *) sobj->data; |
||
775 | const struct elf_type_functions* fns; |
||
776 | unsigned char cl; |
||
777 | size_t shdr_size; |
||
778 | unsigned char buf[sizeof (Elf64_External_Shdr)]; |
||
779 | |||
780 | fns = attrs->type_functions; |
||
781 | cl = attrs->ei_class; |
||
782 | |||
783 | shdr_size = (cl == ELFCLASS32 |
||
784 | ? sizeof (Elf32_External_Shdr) |
||
785 | : sizeof (Elf64_External_Shdr)); |
||
786 | memset (buf, 0, sizeof (Elf64_External_Shdr)); |
||
787 | |||
788 | ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name); |
||
789 | ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type); |
||
790 | ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags); |
||
791 | ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset); |
||
792 | ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size); |
||
6324 | serge | 793 | ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link); |
5191 | serge | 794 | /* sh_info left as zero. */ |
795 | ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign); |
||
796 | /* sh_entsize left as zero. */ |
||
797 | |||
798 | return simple_object_internal_write (descriptor, offset, buf, shdr_size, |
||
799 | errmsg, err); |
||
800 | } |
||
801 | |||
802 | /* Write out a complete ELF file. |
||
803 | Ehdr |
||
804 | initial dummy Shdr |
||
805 | user-created Shdrs |
||
806 | .shstrtab Shdr |
||
807 | user-created section data |
||
808 | .shstrtab data */ |
||
809 | |||
810 | static const char * |
||
811 | simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, |
||
812 | int *err) |
||
813 | { |
||
814 | struct simple_object_elf_attributes *attrs = |
||
815 | (struct simple_object_elf_attributes *) sobj->data; |
||
816 | unsigned char cl; |
||
817 | size_t ehdr_size; |
||
818 | size_t shdr_size; |
||
819 | const char *errmsg; |
||
820 | simple_object_write_section *section; |
||
821 | unsigned int shnum; |
||
822 | size_t shdr_offset; |
||
823 | size_t sh_offset; |
||
6324 | serge | 824 | unsigned int first_sh_size; |
825 | unsigned int first_sh_link; |
||
5191 | serge | 826 | size_t sh_name; |
827 | unsigned char zero; |
||
828 | |||
829 | if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err)) |
||
830 | return errmsg; |
||
831 | |||
832 | cl = attrs->ei_class; |
||
833 | if (cl == ELFCLASS32) |
||
834 | { |
||
835 | ehdr_size = sizeof (Elf32_External_Ehdr); |
||
836 | shdr_size = sizeof (Elf32_External_Shdr); |
||
837 | } |
||
838 | else |
||
839 | { |
||
840 | ehdr_size = sizeof (Elf64_External_Ehdr); |
||
841 | shdr_size = sizeof (Elf64_External_Shdr); |
||
842 | } |
||
843 | |||
844 | shnum = 0; |
||
845 | for (section = sobj->sections; section != NULL; section = section->next) |
||
846 | ++shnum; |
||
847 | if (shnum == 0) |
||
848 | return NULL; |
||
849 | |||
850 | /* Add initial dummy Shdr and .shstrtab. */ |
||
851 | shnum += 2; |
||
852 | |||
853 | shdr_offset = ehdr_size; |
||
854 | sh_offset = shdr_offset + shnum * shdr_size; |
||
855 | |||
6324 | serge | 856 | if (shnum < SHN_LORESERVE) |
857 | first_sh_size = 0; |
||
858 | else |
||
859 | first_sh_size = shnum; |
||
860 | if (shnum - 1 < SHN_LORESERVE) |
||
861 | first_sh_link = 0; |
||
862 | else |
||
863 | first_sh_link = shnum - 1; |
||
5191 | serge | 864 | if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, |
6324 | serge | 865 | 0, 0, 0, 0, first_sh_size, first_sh_link, |
866 | 0, &errmsg, err)) |
||
5191 | serge | 867 | return errmsg; |
868 | |||
869 | shdr_offset += shdr_size; |
||
870 | |||
871 | sh_name = 1; |
||
872 | for (section = sobj->sections; section != NULL; section = section->next) |
||
873 | { |
||
874 | size_t mask; |
||
875 | size_t new_sh_offset; |
||
876 | size_t sh_size; |
||
877 | struct simple_object_write_section_buffer *buffer; |
||
878 | |||
879 | mask = (1U << section->align) - 1; |
||
880 | new_sh_offset = sh_offset + mask; |
||
881 | new_sh_offset &= ~ mask; |
||
882 | while (new_sh_offset > sh_offset) |
||
883 | { |
||
884 | unsigned char zeroes[16]; |
||
885 | size_t write; |
||
886 | |||
887 | memset (zeroes, 0, sizeof zeroes); |
||
888 | write = new_sh_offset - sh_offset; |
||
889 | if (write > sizeof zeroes) |
||
890 | write = sizeof zeroes; |
||
891 | if (!simple_object_internal_write (descriptor, sh_offset, zeroes, |
||
892 | write, &errmsg, err)) |
||
893 | return errmsg; |
||
894 | sh_offset += write; |
||
895 | } |
||
896 | |||
897 | sh_size = 0; |
||
898 | for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) |
||
899 | { |
||
900 | if (!simple_object_internal_write (descriptor, sh_offset + sh_size, |
||
901 | ((const unsigned char *) |
||
902 | buffer->buffer), |
||
903 | buffer->size, &errmsg, err)) |
||
904 | return errmsg; |
||
905 | sh_size += buffer->size; |
||
906 | } |
||
907 | |||
908 | if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, |
||
909 | sh_name, SHT_PROGBITS, 0, sh_offset, |
||
6324 | serge | 910 | sh_size, 0, 1U << section->align, |
5191 | serge | 911 | &errmsg, err)) |
912 | return errmsg; |
||
913 | |||
914 | shdr_offset += shdr_size; |
||
915 | sh_name += strlen (section->name) + 1; |
||
916 | sh_offset += sh_size; |
||
917 | } |
||
918 | |||
919 | if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, |
||
920 | sh_name, SHT_STRTAB, 0, sh_offset, |
||
6324 | serge | 921 | sh_name + strlen (".shstrtab") + 1, 0, |
5191 | serge | 922 | 1, &errmsg, err)) |
923 | return errmsg; |
||
924 | |||
925 | /* .shstrtab has a leading zero byte. */ |
||
926 | zero = 0; |
||
927 | if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1, |
||
928 | &errmsg, err)) |
||
929 | return errmsg; |
||
930 | ++sh_offset; |
||
931 | |||
932 | for (section = sobj->sections; section != NULL; section = section->next) |
||
933 | { |
||
934 | size_t len; |
||
935 | |||
936 | len = strlen (section->name) + 1; |
||
937 | if (!simple_object_internal_write (descriptor, sh_offset, |
||
938 | (const unsigned char *) section->name, |
||
939 | len, &errmsg, err)) |
||
940 | return errmsg; |
||
941 | sh_offset += len; |
||
942 | } |
||
943 | |||
944 | if (!simple_object_internal_write (descriptor, sh_offset, |
||
945 | (const unsigned char *) ".shstrtab", |
||
946 | strlen (".shstrtab") + 1, &errmsg, err)) |
||
947 | return errmsg; |
||
948 | |||
949 | return NULL; |
||
950 | } |
||
951 | |||
952 | /* Release the private data for an simple_object_write structure. */ |
||
953 | |||
954 | static void |
||
955 | simple_object_elf_release_write (void *data) |
||
956 | { |
||
957 | XDELETE (data); |
||
958 | } |
||
959 | |||
960 | /* The ELF functions. */ |
||
961 | |||
962 | const struct simple_object_functions simple_object_elf_functions = |
||
963 | { |
||
964 | simple_object_elf_match, |
||
965 | simple_object_elf_find_sections, |
||
966 | simple_object_elf_fetch_attributes, |
||
967 | simple_object_elf_release_read, |
||
968 | simple_object_elf_attributes_merge, |
||
969 | simple_object_elf_release_attributes, |
||
970 | simple_object_elf_start_write, |
||
971 | simple_object_elf_write_to_file, |
||
972 | simple_object_elf_release_write |
||
973 | };><>><>>>> |