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]
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>
44 * This module is compiled to support 32-bit and 64-bit class objects. Define
45 * the necessary interfaces for these classes.
49 #define output output64
52 #define output output32
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
},
63 * Process all input files. These contain the data that will be assigned to a
67 input(int argc
, char **argv
, const char *prog
, const char *ofile
,
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
81 for (ndx
= 1; argc
; argc
--, argv
++, ndx
++) {
87 * Close any previously opened file.
93 * Identify the section.
95 outsec
.os_name
= basename(file
);
96 outsec
.os_type
= SHT_PROGBITS
;
97 outsec
.os_flags
= SHF_ALLOC
;
100 if ((fd
= open(file
, O_RDONLY
)) == -1) {
102 (void) fprintf(stderr
, MSG_INTL(MSG_ERR_OPEN
),
103 prog
, file
, strerror(err
));
107 if (fstat(fd
, &status
) == -1) {
109 (void) fprintf(stderr
, MSG_INTL(MSG_ERR_FSTAT
),
110 prog
, file
, strerror(err
));
115 if ((outsec
.os_size
= status
.st_size
) == 0) {
116 (void) fprintf(stderr
, MSG_INTL(MSG_WARN_ZERO
),
121 if ((outsec
.os_addr
= mmap(NULL
, outsec
.os_size
, PROT_READ
,
122 MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) {
124 (void) fprintf(stderr
, MSG_INTL(MSG_ERR_MMAP
),
125 prog
, file
, strerror(err
));
130 if (alist_append(&(odp
->od_outsecs
), &outsec
, sizeof (OutSec_t
),
131 AL_CNT_WOSECS
) == 0) {
133 (void) fprintf(stderr
, MSG_INTL(MSG_ERR_ALLOC
),
134 prog
, file
, strerror(err
));
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
);
160 * If an error occurred, or no input files contributed data, bail now.
162 if (ret
|| (odp
->od_outsecs
== NULL
))
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
;
181 if (alist_append(&(odp
->od_outsecs
), &outsec
, sizeof (OutSec_t
),
182 AL_CNT_WOSECS
) == 0) {
184 (void) fprintf(stderr
, MSG_INTL(MSG_ERR_ALLOC
),
185 prog
, outsec
.os_name
, strerror(err
));
190 * Each standard section contributes:
192 * i. its section name to the .shstrtab.
193 * ii. a section symbol.
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
++;
212 * Having captured all input data, create the output file.
215 output(const char *prog
, int fd
, const char *ofile
, ushort_t mach
,
221 Sym
*symtab
, *secsymtabent
, *glbsymtabent
;
222 char *strtab
, *strtabent
, *shstrtab
, *shstrtabent
;
223 OutSec_t
*outsec
, *outsymtab
, *outstrtab
, *outshstrtab
;
228 * Obtain any target specific ELF information.
235 target_init_sparc(&tdesc
);
238 target_init_sparcv9(&tdesc
);
241 target_init_i386(&tdesc
);
244 target_init_amd64(&tdesc
);
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()));
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()));
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
)) {
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()));
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()));
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()));
309 switch (shdr
->sh_type
) {
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
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
;
325 * If this is the symbol table, use the symbol count to
326 * reserve sufficient space for the symbols we need.
329 data
->d_type
= ELF_T_SYM
;
330 data
->d_size
= (odp
->od_symtabno
* tdesc
.td_symsz
);
331 data
->d_align
= tdesc
.td_align
;
336 * If this is a string table, use the table size to
337 * reserve sufficient space for the strings we need.
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
;
344 data
->d_size
= odp
->od_strtabsz
;
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()));
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()));
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()));
378 * Read the section header and data from the new sections of the
381 for (ALIST_TRAVERSE(odp
->od_outsecs
, off
, outsec
)) {
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()));
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()));
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()));
401 if (shdr
->sh_type
== SHT_PROGBITS
)
405 * Remember the symbol table and string tables, so that they
406 * can be filled in later.
408 if (shdr
->sh_type
== SHT_SYMTAB
) {
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
;
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.
433 shstrtabent
= shstrtab
;
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
;
443 secsymtabent
->st_name
= (strtabent
- strtab
);
444 secsymtabent
->st_info
= ELF_ST_INFO(STB_LOCAL
, STT_NOTYPE
);
445 secsymtabent
->st_shndx
= SHN_ABS
;
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
);
461 * Rescan all the new sections, adding symbols and strings as required.
463 for (ALIST_TRAVERSE(odp
->od_outsecs
, off
, outsec
)) {
467 * Create a section symbol.
469 secsymtabent
->st_info
= ELF_ST_INFO(STB_LOCAL
, STT_SECTION
);
470 secsymtabent
->st_shndx
= outsec
->os_ndx
;
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
),
483 shstrtabent
+= MSG_STR_DOT_SIZE
;
486 len
= strlen(outsec
->os_name
) + 1;
487 (void) memcpy(shstrtabent
, outsec
->os_name
, len
);
490 if (outsec
->os_shdr
->sh_type
!= SHT_PROGBITS
)
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
;
506 * Store this symbol name (with an appended "_data") in the
510 (void) memcpy(strtabent
, outsec
->os_name
, len
);
512 alen
= (MSG_STR_START_SIZE
+ 1);
513 (void) memcpy(strtabent
, MSG_ORIG(MSG_STR_START
), 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
;
526 * Store this symbol name (with an appended "_end") in the
529 (void) memcpy(strtabent
, outsec
->os_name
, len
);
531 alen
= (MSG_STR_END_SIZE
+ 1);
532 (void) memcpy(strtabent
, MSG_ORIG(MSG_STR_END
), 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()));
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()));
571 (void) elf_end(oelf
);