1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/mman.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <libgen.h>
33 #include <errno.h>
34 #include <libelf.h>
35 #include <stdio.h>
36 #include <strings.h>
37 #include <msg.h>
38 #include <machdep.h>
39 #include <_libelf.h>
40 #include <_elfwrap.h>
41
42 /*
43 * This module is compiled to support 32-bit and 64-bit class objects. Define
44 * the necessary interfaces for these classes.
45 */
46 #if defined(_ELF64)
47 #define input input64
48 #define output output64
49 #else
50 #define input input32
51 #define output output32
52 #endif
53
54 static StdSec_t StdSecs[] = {
55 { MSG_ORIG(MSG_SCN_SYMTAB), SHT_SYMTAB, 0 },
56 { MSG_ORIG(MSG_SCN_STRTAB), SHT_STRTAB, SHF_STRINGS},
57 { MSG_ORIG(MSG_SCN_SHSTRTAB), SHT_STRTAB, SHF_STRINGS},
58 { NULL, 0, 0 }
59 };
60
61 /*
62 * Process all input files. These contain the data that will be assigned to a
63 * new ELF section.
64 */
65 int
input(int argc,char ** argv,const char * prog,const char * ofile,ObjDesc_t * odp)66 input(int argc, char **argv, const char *prog, const char *ofile,
67 ObjDesc_t *odp)
68 {
69 OutSec_t outsec;
70 StdSec_t *stdsecs;
71 size_t ndx, cnt;
72 int ret = 0, fd = -1;
73
74 /*
75 * Make sure we have access to read each input file, and prepare an
76 * output section descriptor for each. Note, we assign section indexes
77 * starting at 1, as section index 0 is special, and is created by
78 * libelf.
79 */
80 for (ndx = 1; argc; argc--, argv++, ndx++) {
81 char *file = *argv;
82 struct stat status;
83 size_t namesz;
84
85 /*
86 * Close any previously opened file.
87 */
88 if (fd != -1)
89 (void) close(fd);
90
91 /*
92 * Identify the section.
93 */
94 outsec.os_name = basename(file);
95 outsec.os_type = SHT_PROGBITS;
96 outsec.os_flags = SHF_ALLOC;
97 outsec.os_ndx = ndx;
98
99 if ((fd = open(file, O_RDONLY)) == -1) {
100 int err = errno;
101 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
102 prog, file, strerror(err));
103 ret = 1;
104 continue;
105 }
106 if (fstat(fd, &status) == -1) {
107 int err = errno;
108 (void) fprintf(stderr, MSG_INTL(MSG_ERR_FSTAT),
109 prog, file, strerror(err));
110 ret = 1;
111 continue;
112 }
113
114 if ((outsec.os_size = status.st_size) == 0) {
115 (void) fprintf(stderr, MSG_INTL(MSG_WARN_ZERO),
116 prog, file);
117 continue;
118 }
119
120 if ((outsec.os_addr = mmap(0, outsec.os_size, PROT_READ,
121 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
122 int err = errno;
123 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MMAP),
124 prog, file, strerror(err));
125 ret = 1;
126 continue;
127 }
128
129 if (alist_append(&(odp->od_outsecs), &outsec, sizeof (OutSec_t),
130 AL_CNT_WOSECS) == 0) {
131 int err = errno;
132 (void) fprintf(stderr, MSG_INTL(MSG_ERR_ALLOC),
133 prog, file, strerror(err));
134 return (1);
135 }
136
137 /*
138 * Each data section contributes:
139 *
140 * i. its basename, prefixed with a "dot", to the .shstrtab.
141 * ii. a section symbol.
142 * iii. a data symbol, using the basename, with an
143 * appended "_data" string.
144 * iv. a data size symbol, using the basename with an
145 * appended "_size" string.
146 */
147 namesz = strlen(outsec.os_name) + 1;
148
149 odp->od_symtabno += 3;
150 odp->od_strtabsz += (namesz + MSG_STR_START_SIZE);
151 odp->od_strtabsz += (namesz + MSG_STR_END_SIZE);
152 odp->od_shstrtabsz += (namesz + MSG_STR_DOT_SIZE);
153 }
154
155 if (fd != -1)
156 (void) close(fd);
157
158 /*
159 * If an error occurred, or no input files contributed data, bail now.
160 */
161 if (ret || (odp->od_outsecs == NULL))
162 return (1);
163
164 /*
165 * Create section descriptors for .symtab, .strtab, and .shstrtab.
166 */
167 for (cnt = 0, stdsecs = &StdSecs[cnt]; stdsecs->ss_name; cnt++,
168 ndx++, stdsecs = &StdSecs[cnt]) {
169
170 /*
171 * Identify the section.
172 */
173 outsec.os_name = stdsecs->ss_name;
174 outsec.os_type = stdsecs->ss_type;
175 outsec.os_flags = stdsecs->ss_flags;
176 outsec.os_ndx = ndx;
177 outsec.os_size = 0;
178 outsec.os_addr = 0;
179
180 if (alist_append(&(odp->od_outsecs), &outsec, sizeof (OutSec_t),
181 AL_CNT_WOSECS) == 0) {
182 int err = errno;
183 (void) fprintf(stderr, MSG_INTL(MSG_ERR_ALLOC),
184 prog, outsec.os_name, strerror(err));
185 return (1);
186 }
187
188 /*
189 * Each standard section contributes:
190 *
191 * i. its section name to the .shstrtab.
192 * ii. a section symbol.
193 */
194 odp->od_symtabno++;
195 odp->od_shstrtabsz += (strlen(outsec.os_name) + 1);
196 }
197
198 /*
199 * The symbol table requires an initial NULL entry and a following
200 * FILE entry. Both string tables require an initial NULL byte.
201 * The .strtab requires room for the output file name (STT_FILE).
202 */
203 odp->od_symtabno += 2;
204 odp->od_strtabsz += strlen(ofile) + 2;
205 odp->od_shstrtabsz++;
206
207 return (0);
208 }
209
210 /*
211 * Having captured all input data, create the output file.
212 */
213 int
output(const char * prog,int fd,const char * ofile,ushort_t mach,ObjDesc_t * odp)214 output(const char *prog, int fd, const char *ofile, ushort_t mach,
215 ObjDesc_t *odp)
216 {
217 Aliste off;
218 Elf *melf, *oelf;
219 Ehdr *ehdr;
220 Sym *symtab, *secsymtabent, *glbsymtabent;
221 char *strtab, *strtabent, *shstrtab, *shstrtabent;
222 OutSec_t *outsec, *outsymtab, *outstrtab, *outshstrtab;
223 size_t len;
224 TargDesc_t tdesc;
225
226 /*
227 * Obtain any target specific ELF information.
228 */
229 if (mach == 0)
230 mach = M_MACH;
231
232 switch (mach) {
233 #if !defined(lint)
234 case EM_SPARC:
235 target_init_sparc(&tdesc);
236 break;
237 case EM_SPARCV9:
238 target_init_sparcv9(&tdesc);
239 break;
240 case EM_386:
241 target_init_i386(&tdesc);
242 break;
243 case EM_AMD64:
244 target_init_amd64(&tdesc);
245 break;
246 #else
247 default:
248 target_init(&tdesc);
249 break;
250 #endif
251 }
252 /*
253 * Create a new ELF descriptor for the new output file.
254 */
255 if ((oelf = elf_begin(fd, ELF_C_WRITE, 0)) == NULL) {
256 (void) fprintf(stderr, MSG_INTL(MSG_ELF_BEGIN), prog,
257 elf_errmsg(elf_errno()));
258 return (1);
259 }
260
261 /*
262 * Create and initialize the new ELF header.
263 */
264 if ((ehdr = elf_newehdr(oelf)) == NULL) {
265 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NEWEHDR), prog,
266 elf_errmsg(elf_errno()));
267 return (1);
268 }
269
270 /*
271 * Note, the ELF header is initialized to reflect the host running
272 * elfwrap(1) rather than the target. Using host byte order allows
273 * elfwrap(1) to create the object data. Prior to the final update,
274 * the output ELF header is modified to reflect the target, causing
275 * libelf to produce the output object using the correct byte order
276 * and other target information.
277 */
278 ehdr->e_ident[EI_DATA] = M_DATA;
279 ehdr->e_type = ET_REL;
280 ehdr->e_version = EV_CURRENT;
281
282 /*
283 * Create the required number of new sections, their associated section
284 * header, and an initial data buffer.
285 */
286 for (ALIST_TRAVERSE(odp->od_outsecs, off, outsec)) {
287 Elf_Scn *scn;
288 Elf_Data *data;
289 Shdr *shdr;
290
291 if ((scn = elf_newscn(oelf)) == NULL) {
292 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NEWSCN),
293 prog, outsec->os_name, elf_errmsg(elf_errno()));
294 return (1);
295 }
296 if ((shdr = elf_getshdr(scn)) == NULL) {
297 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSHDR),
298 prog, outsec->os_name, elf_errmsg(elf_errno()));
299 return (1);
300 }
301
302 /*
303 * Assign the section type and flags.
304 */
305 shdr->sh_type = outsec->os_type;
306 shdr->sh_flags = outsec->os_flags;
307
308 if ((data = elf_newdata(scn)) == NULL) {
309 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NEWDATA),
310 prog, outsec->os_name, elf_errmsg(elf_errno()));
311 return (1);
312 }
313
314 switch (shdr->sh_type) {
315 case SHT_PROGBITS:
316 /*
317 * If this is a PROGBITS section, then the data
318 * originates from an input file. Assign the data
319 * buffer to this input file and provide a default
320 * alignment.
321 */
322 data->d_buf = outsec->os_addr;
323 data->d_type = ELF_T_BYTE;
324 data->d_size = outsec->os_size;
325 data->d_align = tdesc.td_align;
326 break;
327
328 case SHT_SYMTAB:
329 /*
330 * If this is the symbol table, use the symbol count to
331 * reserve sufficient space for the symbols we need.
332 */
333 data->d_buf = 0;
334 data->d_type = ELF_T_SYM;
335 data->d_size = (odp->od_symtabno * tdesc.td_symsz);
336 data->d_align = tdesc.td_align;
337 break;
338
339 case SHT_STRTAB:
340 /*
341 * If this is a string table, use the table size to
342 * reserve sufficient space for the strings we need.
343 */
344 data->d_buf = 0;
345 data->d_type = ELF_T_BYTE;
346 if (strcmp(outsec->os_name, MSG_ORIG(MSG_SCN_STRTAB)))
347 data->d_size = odp->od_shstrtabsz;
348 else
349 data->d_size = odp->od_strtabsz;
350 data->d_align = 1;
351 break;
352 }
353 }
354
355 /*
356 * Write the ELF data into a memory image.
357 */
358 if ((elf_update(oelf, ELF_C_WRIMAGE)) == -1) {
359 (void) fprintf(stderr, MSG_INTL(MSG_ELF_UPDATE), prog,
360 elf_errmsg(elf_errno()));
361 return (1);
362 }
363
364 /*
365 * Assign an ELF descriptor to the memory image.
366 */
367 if ((melf = elf_begin(0, ELF_C_IMAGE, oelf)) == NULL) {
368 (void) fprintf(stderr, MSG_INTL(MSG_ELF_BEGIN), prog,
369 elf_errmsg(elf_errno()));
370 return (1);
371 }
372
373 /*
374 * Get the ELF header from the memory image.
375 */
376 if ((ehdr = elf_getehdr(melf)) == NULL) {
377 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETEHDR), prog,
378 elf_errmsg(elf_errno()));
379 return (1);
380 }
381
382 /*
383 * Read the section header and data from the new sections of the
384 * memory image.
385 */
386 for (ALIST_TRAVERSE(odp->od_outsecs, off, outsec)) {
387 Elf_Scn *scn;
388 Shdr *shdr;
389
390 if ((scn = elf_getscn(melf, outsec->os_ndx)) == NULL) {
391 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSCN),
392 prog, outsec->os_name, elf_errmsg(elf_errno()));
393 return (1);
394 }
395 if ((outsec->os_shdr = shdr = elf_getshdr(scn)) == NULL) {
396 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSHDR),
397 prog, outsec->os_name, elf_errmsg(elf_errno()));
398 return (1);
399 }
400 if ((outsec->os_data = elf_getdata(scn, NULL)) == NULL) {
401 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA),
402 prog, outsec->os_name, elf_errmsg(elf_errno()));
403 return (1);
404 }
405
406 if (shdr->sh_type == SHT_PROGBITS)
407 continue;
408
409 /*
410 * Remember the symbol table and string tables, so that they
411 * can be filled in later.
412 */
413 if (shdr->sh_type == SHT_SYMTAB) {
414 outsymtab = outsec;
415 symtab = (Sym *)outsec->os_data->d_buf;
416 } else if (shdr->sh_type == SHT_STRTAB) {
417 if (strcmp(outsec->os_name, MSG_ORIG(MSG_SCN_STRTAB))) {
418 outshstrtab = outsec;
419 shstrtab = (char *)outsec->os_data->d_buf;
420 } else {
421 outstrtab = outsec;
422 strtab = (char *)outsec->os_data->d_buf;
423 }
424 }
425 }
426
427 /*
428 * Update the ELF header with the .shstrtab index.
429 */
430 ehdr->e_shstrndx = outshstrtab->os_ndx;
431
432 /*
433 * Set up the string table entries, and skip the first byte.
434 */
435 strtabent = strtab;
436 strtabent++;
437
438 shstrtabent = shstrtab;
439 shstrtabent++;
440
441 /*
442 * Skip the first symbol table entry. Write a FILE entry, and set
443 * up for adding sections and data symbols. Associate the symbol
444 * table with the string table.
445 */
446 secsymtabent = symtab;
447 secsymtabent++;
448 secsymtabent->st_name = (strtabent - strtab);
449 secsymtabent->st_info = ELF_ST_INFO(STB_LOCAL, STT_NOTYPE);
450 secsymtabent->st_shndx = SHN_ABS;
451 secsymtabent++;
452
453 glbsymtabent = secsymtabent;
454 glbsymtabent += alist_nitems(odp->od_outsecs);
455
456 outsymtab->os_shdr->sh_link = outstrtab->os_ndx;
457
458 /*
459 * Write the output file name to the .strtab.
460 */
461 len = strlen(ofile) + 1;
462 (void) memcpy(strtabent, ofile, len);
463 strtabent += len;
464
465 /*
466 * Rescan all the new sections, adding symbols and strings as required.
467 */
468 for (ALIST_TRAVERSE(odp->od_outsecs, off, outsec)) {
469 size_t alen;
470
471 /*
472 * Create a section symbol.
473 */
474 secsymtabent->st_info = ELF_ST_INFO(STB_LOCAL, STT_SECTION);
475 secsymtabent->st_shndx = outsec->os_ndx;
476 secsymtabent++;
477
478 /*
479 * Store the section name, (with an appended "." if the section
480 * name is derived from the input file name), and point the
481 * section header to this name.
482 */
483 outsec->os_shdr->sh_name = (shstrtabent - shstrtab);
484
485 if (outsec->os_shdr->sh_type == SHT_PROGBITS) {
486 (void) memcpy(shstrtabent, MSG_ORIG(MSG_STR_DOT),
487 MSG_STR_DOT_SIZE);
488 shstrtabent += MSG_STR_DOT_SIZE;
489 }
490
491 len = strlen(outsec->os_name) + 1;
492 (void) memcpy(shstrtabent, outsec->os_name, len);
493 shstrtabent += len;
494
495 if (outsec->os_shdr->sh_type != SHT_PROGBITS)
496 continue;
497
498 /*
499 * Add a symbol pointing to this PROGBITS section. The value
500 * is the base offset of this section, which can only be 0.
501 * The size of the symbol can be taken straight from the section
502 * header information (that libelf generated).
503 */
504 glbsymtabent->st_name = (strtabent - strtab);
505 glbsymtabent->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
506 glbsymtabent->st_shndx = outsec->os_ndx;
507 glbsymtabent->st_size = outsec->os_shdr->sh_size;
508 glbsymtabent++;
509
510 /*
511 * Store this symbol name (with an appended "_data") in the
512 * string table.
513 */
514 len--;
515 (void) memcpy(strtabent, outsec->os_name, len);
516 strtabent += len;
517 alen = (MSG_STR_START_SIZE + 1);
518 (void) memcpy(strtabent, MSG_ORIG(MSG_STR_START), alen);
519 strtabent += alen;
520
521 /*
522 * Add a symbol indicating the size of this PROGBITS section.
523 */
524 glbsymtabent->st_name = (strtabent - strtab);
525 glbsymtabent->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
526 glbsymtabent->st_shndx = outsec->os_ndx;
527 glbsymtabent->st_value = outsec->os_shdr->sh_size;
528 glbsymtabent++;
529
530 /*
531 * Store this symbol name (with an appended "_end") in the
532 * string table.
533 */
534 (void) memcpy(strtabent, outsec->os_name, len);
535 strtabent += len;
536 alen = (MSG_STR_END_SIZE + 1);
537 (void) memcpy(strtabent, MSG_ORIG(MSG_STR_END), alen);
538 strtabent += alen;
539 }
540
541 /*
542 * Update the .symtab section header with the index of the first
543 * non-local symbol. The only locals written are the section symbols.
544 */
545 outsymtab->os_shdr->sh_info = (secsymtabent - symtab);
546
547 /*
548 * Having updated the image following the byte order of elfwrap(), seed
549 * the ELF header with the appropriate target information.
550 */
551 ehdr->e_ident[EI_CLASS] = tdesc.td_class;
552 ehdr->e_ident[EI_DATA] = tdesc.td_data;
553 ehdr->e_machine = tdesc.td_mach;
554
555 /*
556 * If the output relocatable object is targeted to a machine with a
557 * different byte order than the host running elfwrap(1), swap the data
558 * to the target byte order.
559 */
560 if ((_elf_sys_encoding() != ehdr->e_ident[EI_DATA]) &&
561 (_elf_swap_wrimage(melf) != 0)) {
562 (void) fprintf(stderr, MSG_INTL(MSG_ELF_SWAP_WRIMAGE), prog,
563 elf_errmsg(elf_errno()));
564 return (1);
565 }
566 (void) elf_end(melf);
567
568 /*
569 * Finally, write the updated memory image out to disc.
570 */
571 if ((elf_update(oelf, ELF_C_WRITE)) == -1) {
572 (void) fprintf(stderr, MSG_INTL(MSG_ELF_UPDATE), prog,
573 elf_errmsg(elf_errno()));
574 return (1);
575 }
576 (void) elf_end(oelf);
577
578 return (0);
579 }
580