dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / sgs / elfwrap / common / elfwrap.c
blob39953c82ea67631a4ffd5117a96e7896c8050100
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
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>
44 * This module is compiled to support 32-bit and 64-bit class objects. Define
45 * the necessary interfaces for these classes.
47 #if defined(_ELF64)
48 #define input input64
49 #define output output64
50 #else
51 #define input input32
52 #define output output32
53 #endif
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 }
63 * Process all input files. These contain the data that will be assigned to a
64 * new ELF section.
66 int
67 input(int argc, char **argv, const char *prog, const char *ofile,
68 ObjDesc_t *odp)
70 OutSec_t outsec;
71 StdSec_t *stdsecs;
72 size_t ndx, cnt;
73 int ret = 0, fd = -1;
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.
81 for (ndx = 1; argc; argc--, argv++, ndx++) {
82 char *file = *argv;
83 struct stat status;
84 size_t namesz;
87 * Close any previously opened file.
89 if (fd != -1)
90 (void) close(fd);
93 * Identify the section.
95 outsec.os_name = basename(file);
96 outsec.os_type = SHT_PROGBITS;
97 outsec.os_flags = SHF_ALLOC;
98 outsec.os_ndx = ndx;
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;
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;
115 if ((outsec.os_size = status.st_size) == 0) {
116 (void) fprintf(stderr, MSG_INTL(MSG_WARN_ZERO),
117 prog, file);
118 continue;
121 if ((outsec.os_addr = mmap(NULL, 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;
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);
139 * Each data section contributes:
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.
148 namesz = strlen(outsec.os_name) + 1;
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);
156 if (fd != -1)
157 (void) close(fd);
160 * If an error occurred, or no input files contributed data, bail now.
162 if (ret || (odp->od_outsecs == NULL))
163 return (1);
166 * Create section descriptors for .symtab, .strtab, and .shstrtab.
168 for (cnt = 0, stdsecs = &StdSecs[cnt]; stdsecs->ss_name; cnt++,
169 ndx++, stdsecs = &StdSecs[cnt]) {
172 * Identify the section.
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;
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);
190 * Each standard section contributes:
192 * i. its section name to the .shstrtab.
193 * ii. a section symbol.
195 odp->od_symtabno++;
196 odp->od_shstrtabsz += (strlen(outsec.os_name) + 1);
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).
204 odp->od_symtabno += 2;
205 odp->od_strtabsz += strlen(ofile) + 2;
206 odp->od_shstrtabsz++;
208 return (0);
212 * Having captured all input data, create the output file.
215 output(const char *prog, int fd, const char *ofile, ushort_t mach,
216 ObjDesc_t *odp)
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;
228 * Obtain any target specific ELF information.
230 if (mach == 0)
231 mach = M_MACH;
233 switch (mach) {
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;
248 * Create a new ELF descriptor for the new output file.
250 if ((oelf = elf_begin(fd, ELF_C_WRITE, 0)) == NULL) {
251 (void) fprintf(stderr, MSG_INTL(MSG_ELF_BEGIN), prog,
252 elf_errmsg(elf_errno()));
253 return (1);
257 * Create and initialize the new ELF header.
259 if ((ehdr = elf_newehdr(oelf)) == NULL) {
260 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NEWEHDR), prog,
261 elf_errmsg(elf_errno()));
262 return (1);
266 * Note, the ELF header is initialized to reflect the host running
267 * elfwrap(1) rather than the target. Using host byte order allows
268 * elfwrap(1) to create the object data. Prior to the final update,
269 * the output ELF header is modified to reflect the target, causing
270 * libelf to produce the output object using the correct byte order
271 * and other target information.
273 ehdr->e_ident[EI_DATA] = M_DATA;
274 ehdr->e_type = ET_REL;
275 ehdr->e_version = EV_CURRENT;
278 * Create the required number of new sections, their associated section
279 * header, and an initial data buffer.
281 for (ALIST_TRAVERSE(odp->od_outsecs, off, outsec)) {
282 Elf_Scn *scn;
283 Elf_Data *data;
284 Shdr *shdr;
286 if ((scn = elf_newscn(oelf)) == NULL) {
287 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NEWSCN),
288 prog, outsec->os_name, elf_errmsg(elf_errno()));
289 return (1);
291 if ((shdr = elf_getshdr(scn)) == NULL) {
292 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSHDR),
293 prog, outsec->os_name, elf_errmsg(elf_errno()));
294 return (1);
298 * Assign the section type and flags.
300 shdr->sh_type = outsec->os_type;
301 shdr->sh_flags = outsec->os_flags;
303 if ((data = elf_newdata(scn)) == NULL) {
304 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NEWDATA),
305 prog, outsec->os_name, elf_errmsg(elf_errno()));
306 return (1);
309 switch (shdr->sh_type) {
310 case SHT_PROGBITS:
312 * If this is a PROGBITS section, then the data
313 * originates from an input file. Assign the data
314 * buffer to this input file and provide a default
315 * alignment.
317 data->d_buf = outsec->os_addr;
318 data->d_type = ELF_T_BYTE;
319 data->d_size = outsec->os_size;
320 data->d_align = tdesc.td_align;
321 break;
323 case SHT_SYMTAB:
325 * If this is the symbol table, use the symbol count to
326 * reserve sufficient space for the symbols we need.
328 data->d_buf = 0;
329 data->d_type = ELF_T_SYM;
330 data->d_size = (odp->od_symtabno * tdesc.td_symsz);
331 data->d_align = tdesc.td_align;
332 break;
334 case SHT_STRTAB:
336 * If this is a string table, use the table size to
337 * reserve sufficient space for the strings we need.
339 data->d_buf = 0;
340 data->d_type = ELF_T_BYTE;
341 if (strcmp(outsec->os_name, MSG_ORIG(MSG_SCN_STRTAB)))
342 data->d_size = odp->od_shstrtabsz;
343 else
344 data->d_size = odp->od_strtabsz;
345 data->d_align = 1;
346 break;
351 * Write the ELF data into a memory image.
353 if ((elf_update(oelf, ELF_C_WRIMAGE)) == -1) {
354 (void) fprintf(stderr, MSG_INTL(MSG_ELF_UPDATE), prog,
355 elf_errmsg(elf_errno()));
356 return (1);
360 * Assign an ELF descriptor to the memory image.
362 if ((melf = elf_begin(0, ELF_C_IMAGE, oelf)) == NULL) {
363 (void) fprintf(stderr, MSG_INTL(MSG_ELF_BEGIN), prog,
364 elf_errmsg(elf_errno()));
365 return (1);
369 * Get the ELF header from the memory image.
371 if ((ehdr = elf_getehdr(melf)) == NULL) {
372 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETEHDR), prog,
373 elf_errmsg(elf_errno()));
374 return (1);
378 * Read the section header and data from the new sections of the
379 * memory image.
381 for (ALIST_TRAVERSE(odp->od_outsecs, off, outsec)) {
382 Elf_Scn *scn;
383 Shdr *shdr;
385 if ((scn = elf_getscn(melf, outsec->os_ndx)) == NULL) {
386 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSCN),
387 prog, outsec->os_name, elf_errmsg(elf_errno()));
388 return (1);
390 if ((outsec->os_shdr = shdr = elf_getshdr(scn)) == NULL) {
391 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETSHDR),
392 prog, outsec->os_name, elf_errmsg(elf_errno()));
393 return (1);
395 if ((outsec->os_data = elf_getdata(scn, NULL)) == NULL) {
396 (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA),
397 prog, outsec->os_name, elf_errmsg(elf_errno()));
398 return (1);
401 if (shdr->sh_type == SHT_PROGBITS)
402 continue;
405 * Remember the symbol table and string tables, so that they
406 * can be filled in later.
408 if (shdr->sh_type == SHT_SYMTAB) {
409 outsymtab = outsec;
410 symtab = (Sym *)outsec->os_data->d_buf;
411 } else if (shdr->sh_type == SHT_STRTAB) {
412 if (strcmp(outsec->os_name, MSG_ORIG(MSG_SCN_STRTAB))) {
413 outshstrtab = outsec;
414 shstrtab = (char *)outsec->os_data->d_buf;
415 } else {
416 outstrtab = outsec;
417 strtab = (char *)outsec->os_data->d_buf;
423 * Update the ELF header with the .shstrtab index.
425 ehdr->e_shstrndx = outshstrtab->os_ndx;
428 * Set up the string table entries, and skip the first byte.
430 strtabent = strtab;
431 strtabent++;
433 shstrtabent = shstrtab;
434 shstrtabent++;
437 * Skip the first symbol table entry. Write a FILE entry, and set
438 * up for adding sections and data symbols. Associate the symbol
439 * table with the string table.
441 secsymtabent = symtab;
442 secsymtabent++;
443 secsymtabent->st_name = (strtabent - strtab);
444 secsymtabent->st_info = ELF_ST_INFO(STB_LOCAL, STT_NOTYPE);
445 secsymtabent->st_shndx = SHN_ABS;
446 secsymtabent++;
448 glbsymtabent = secsymtabent;
449 glbsymtabent += alist_nitems(odp->od_outsecs);
451 outsymtab->os_shdr->sh_link = outstrtab->os_ndx;
454 * Write the output file name to the .strtab.
456 len = strlen(ofile) + 1;
457 (void) memcpy(strtabent, ofile, len);
458 strtabent += len;
461 * Rescan all the new sections, adding symbols and strings as required.
463 for (ALIST_TRAVERSE(odp->od_outsecs, off, outsec)) {
464 size_t alen;
467 * Create a section symbol.
469 secsymtabent->st_info = ELF_ST_INFO(STB_LOCAL, STT_SECTION);
470 secsymtabent->st_shndx = outsec->os_ndx;
471 secsymtabent++;
474 * Store the section name, (with an appended "." if the section
475 * name is derived from the input file name), and point the
476 * section header to this name.
478 outsec->os_shdr->sh_name = (shstrtabent - shstrtab);
480 if (outsec->os_shdr->sh_type == SHT_PROGBITS) {
481 (void) memcpy(shstrtabent, MSG_ORIG(MSG_STR_DOT),
482 MSG_STR_DOT_SIZE);
483 shstrtabent += MSG_STR_DOT_SIZE;
486 len = strlen(outsec->os_name) + 1;
487 (void) memcpy(shstrtabent, outsec->os_name, len);
488 shstrtabent += len;
490 if (outsec->os_shdr->sh_type != SHT_PROGBITS)
491 continue;
494 * Add a symbol pointing to this PROGBITS section. The value
495 * is the base offset of this section, which can only be 0.
496 * The size of the symbol can be taken straight from the section
497 * header information (that libelf generated).
499 glbsymtabent->st_name = (strtabent - strtab);
500 glbsymtabent->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
501 glbsymtabent->st_shndx = outsec->os_ndx;
502 glbsymtabent->st_size = outsec->os_shdr->sh_size;
503 glbsymtabent++;
506 * Store this symbol name (with an appended "_data") in the
507 * string table.
509 len--;
510 (void) memcpy(strtabent, outsec->os_name, len);
511 strtabent += len;
512 alen = (MSG_STR_START_SIZE + 1);
513 (void) memcpy(strtabent, MSG_ORIG(MSG_STR_START), alen);
514 strtabent += alen;
517 * Add a symbol indicating the size of this PROGBITS section.
519 glbsymtabent->st_name = (strtabent - strtab);
520 glbsymtabent->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
521 glbsymtabent->st_shndx = outsec->os_ndx;
522 glbsymtabent->st_value = outsec->os_shdr->sh_size;
523 glbsymtabent++;
526 * Store this symbol name (with an appended "_end") in the
527 * string table.
529 (void) memcpy(strtabent, outsec->os_name, len);
530 strtabent += len;
531 alen = (MSG_STR_END_SIZE + 1);
532 (void) memcpy(strtabent, MSG_ORIG(MSG_STR_END), alen);
533 strtabent += alen;
537 * Update the .symtab section header with the index of the first
538 * non-local symbol. The only locals written are the section symbols.
540 outsymtab->os_shdr->sh_info = (secsymtabent - symtab);
543 * Having updated the image following the byte order of elfwrap(), seed
544 * the ELF header with the appropriate target information.
546 ehdr->e_ident[EI_CLASS] = tdesc.td_class;
547 ehdr->e_ident[EI_DATA] = tdesc.td_data;
548 ehdr->e_machine = tdesc.td_mach;
551 * If the output relocatable object is targeted to a machine with a
552 * different byte order than the host running elfwrap(1), swap the data
553 * to the target byte order.
555 if ((_elf_sys_encoding() != ehdr->e_ident[EI_DATA]) &&
556 (_elf_swap_wrimage(melf) != 0)) {
557 (void) fprintf(stderr, MSG_INTL(MSG_ELF_SWAP_WRIMAGE), prog,
558 elf_errmsg(elf_errno()));
559 return (1);
561 (void) elf_end(melf);
564 * Finally, write the updated memory image out to disc.
566 if ((elf_update(oelf, ELF_C_WRITE)) == -1) {
567 (void) fprintf(stderr, MSG_INTL(MSG_ELF_UPDATE), prog,
568 elf_errmsg(elf_errno()));
569 return (1);
571 (void) elf_end(oelf);
573 return (0);