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