17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
59d6538abSab196087 * Common Development and Distribution License (the "License").
69d6538abSab196087 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21ba7866cdSAli Bahrami
227c478bd9Sstevel@tonic-gate /*
23ba7866cdSAli Bahrami * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * Copyright (c) 1988 AT&T
287c478bd9Sstevel@tonic-gate * All Rights Reserved
297c478bd9Sstevel@tonic-gate *
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
32ba7866cdSAli Bahrami #include <sys/sendfile.h>
337c478bd9Sstevel@tonic-gate #include "inc.h"
34ba7866cdSAli Bahrami #include "gelf.h"
357c478bd9Sstevel@tonic-gate
36ba7866cdSAli Bahrami /*
37ba7866cdSAli Bahrami * List of archive members, accessed globally by cmd and file.
38ba7866cdSAli Bahrami */
39ba7866cdSAli Bahrami ARFILE *listhead, *listend;
407c478bd9Sstevel@tonic-gate
41ba7866cdSAli Bahrami /*
42ba7866cdSAli Bahrami * Type used to manage string tables. Archives can have two of these:
43ba7866cdSAli Bahrami *
44ba7866cdSAli Bahrami * sym_strtbl: String table included at the end of the symbol table
45ba7866cdSAli Bahrami * archive member, following the offset array.
46ba7866cdSAli Bahrami *
47ba7866cdSAli Bahrami * long_strtbl: String table used to hold member names that exceed 15
48ba7866cdSAli Bahrami * characters in length, found in the long names archive member.
49ba7866cdSAli Bahrami */
50ba7866cdSAli Bahrami typedef struct {
51ba7866cdSAli Bahrami char *base; /* Base of string table memory */
52ba7866cdSAli Bahrami size_t used; /* # bytes used from allocation */
53ba7866cdSAli Bahrami size_t size; /* Size of allocation */
54ba7866cdSAli Bahrami } ARSTRTBL;
55ba7866cdSAli Bahrami
56ba7866cdSAli Bahrami static ARSTRTBL sym_strtbl;
57ba7866cdSAli Bahrami static ARSTRTBL long_strtbl;
58ba7866cdSAli Bahrami
59ba7866cdSAli Bahrami
60ba7866cdSAli Bahrami /*
61ba7866cdSAli Bahrami * Name and file descriptor used when creating a new archive.
62ba7866cdSAli Bahrami * If this variable references an open file when exit_cleanup()
63ba7866cdSAli Bahrami * executes, it will close and remove the file, preventing incomplete
64ba7866cdSAli Bahrami * temporary files from being left behind in the case of a failure
65ba7866cdSAli Bahrami * or interruption.
66ba7866cdSAli Bahrami */
67ba7866cdSAli Bahrami static struct {
68ba7866cdSAli Bahrami int fd; /* -1, or open file descriptor */
69ba7866cdSAli Bahrami const char *path; /* Path to open file */
70ba7866cdSAli Bahrami } ar_outfile;
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate /*
739d6538abSab196087 * The ar file format requires objects to be padded to an even size.
749d6538abSab196087 * We do that, but it turns out to be beneficial to go farther.
759d6538abSab196087 *
769d6538abSab196087 * ld(1) accesses archives by mmapping them into memory. If the mapped
77ba7866cdSAli Bahrami * objects (member data) have the proper alignment, we can access them
78ba7866cdSAli Bahrami * directly. If the data alignment is wrong, libelf "slides" them over the
79ba7866cdSAli Bahrami * archive header to correct the misalignment. This is expensive in time
80ba7866cdSAli Bahrami * (to copy memory) and space (it causes swap to be allocated by the system
81ba7866cdSAli Bahrami * to back the now-modified pages). Hence, we really want to ensure that
82ba7866cdSAli Bahrami * the alignment is right.
839d6538abSab196087 *
849d6538abSab196087 * We used to align 32-bit objects at 4-byte boundaries, and 64-bit objects
859d6538abSab196087 * at 8-byte. More recently, an elf section type has appeared that has
869d6538abSab196087 * 8-byte alignment requirements (SUNW_move) even in 32-bit objects. So,
879d6538abSab196087 * the current strategy is to align all objects to 8-bytes.
889d6538abSab196087 *
899d6538abSab196087 * There are two important things to consider when setting this value:
909d6538abSab196087 * 1) If a new elf section that ld(1) accesses in memory appears
919d6538abSab196087 * with a greater than 8-byte alignment requirement, this value
929d6538abSab196087 * will need to be raised. Or, alternatively, the entire approach may
939d6538abSab196087 * need reconsideration.
949d6538abSab196087 * 2) The size of this padding must be smaller than the size of the
959d6538abSab196087 * smallest possible ELF section. Otherwise, the logic contained
969d6538abSab196087 * in recover_padding() can be tricked.
979d6538abSab196087 */
989d6538abSab196087 #define PADSZ 8
999d6538abSab196087
1009d6538abSab196087 /*
101ba7866cdSAli Bahrami * Forward Declarations
1027c478bd9Sstevel@tonic-gate */
103ba7866cdSAli Bahrami static void arwrite(const char *, int, const char *, size_t);
104ba7866cdSAli Bahrami static size_t mklong_tab();
105ba7866cdSAli Bahrami static size_t mksymtab(const char *, ARFILEP **, int *);
106ba7866cdSAli Bahrami static const char *make_tmpname(const char *);
107ba7866cdSAli Bahrami static size_t sizeof_symtbl(size_t, int, size_t);
108ba7866cdSAli Bahrami static void savelongname(ARFILE *);
1097c478bd9Sstevel@tonic-gate static void savename(char *);
110ba7866cdSAli Bahrami static int search_sym_tab(const char *, ARFILE *, Elf *,
111ba7866cdSAli Bahrami Elf_Scn *, size_t *, ARFILEP **, size_t *);
112ba7866cdSAli Bahrami static size_t sizeofmembers(size_t);
113ba7866cdSAli Bahrami static char *sputl32(uint32_t, char *);
114ba7866cdSAli Bahrami static char *sputl64(uint64_t, char *);
115ba7866cdSAli Bahrami static void strtbl_pad(ARSTRTBL *, size_t, int);
116ba7866cdSAli Bahrami static char *trimslash(char *s);
117ba7866cdSAli Bahrami static void writesymtab(const char *, int fd, size_t, ARFILEP *,
118ba7866cdSAli Bahrami size_t);
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate
121ba7866cdSAli Bahrami /*
122ba7866cdSAli Bahrami * Function to be called on exit to clean up incomplete new archive.
123ba7866cdSAli Bahrami */
124ba7866cdSAli Bahrami static void
exit_cleanup(void)125ba7866cdSAli Bahrami exit_cleanup(void)
126ba7866cdSAli Bahrami {
127ba7866cdSAli Bahrami if (ar_outfile.fd != -1) {
128ba7866cdSAli Bahrami /* Both of these system calls are Async-Signal-Safe */
129ba7866cdSAli Bahrami (void) close(ar_outfile.fd);
130ba7866cdSAli Bahrami (void) unlink(ar_outfile.path);
131ba7866cdSAli Bahrami }
132ba7866cdSAli Bahrami }
133ba7866cdSAli Bahrami
134ba7866cdSAli Bahrami /*
135ba7866cdSAli Bahrami * Open an existing archive.
136ba7866cdSAli Bahrami */
1377c478bd9Sstevel@tonic-gate int
getaf(Cmd_info * cmd_info)1387c478bd9Sstevel@tonic-gate getaf(Cmd_info *cmd_info)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate Elf_Cmd cmd;
1417c478bd9Sstevel@tonic-gate int fd;
1427c478bd9Sstevel@tonic-gate char *arnam = cmd_info->arnam;
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE) {
145ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_ELF_VERSION),
146ba7866cdSAli Bahrami elf_errmsg(-1));
1477c478bd9Sstevel@tonic-gate exit(1);
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate if ((cmd_info->afd = fd = open(arnam, O_RDONLY)) == -1) {
151ba7866cdSAli Bahrami int err = errno;
152ba7866cdSAli Bahrami
153ba7866cdSAli Bahrami if (err == ENOENT) {
1547c478bd9Sstevel@tonic-gate /* archive does not exist yet, may have to create one */
1557c478bd9Sstevel@tonic-gate return (fd);
1567c478bd9Sstevel@tonic-gate } else {
1577c478bd9Sstevel@tonic-gate /* problem other than "does not exist" */
158ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
159ba7866cdSAli Bahrami arnam, strerror(err));
1607c478bd9Sstevel@tonic-gate exit(1);
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate cmd = ELF_C_READ;
1657c478bd9Sstevel@tonic-gate cmd_info->arf = elf_begin(fd, cmd, (Elf *)0);
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate if (elf_kind(cmd_info->arf) != ELF_K_AR) {
168ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_NOT_ARCHIVE), arnam);
169ba7866cdSAli Bahrami if (cmd_info->opt_flgs & (a_FLAG | b_FLAG))
170ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_USAGE_06),
171ba7866cdSAli Bahrami cmd_info->ponam);
1727c478bd9Sstevel@tonic-gate exit(1);
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate return (fd);
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate
17730a4e2aaSab196087 /*
178ba7866cdSAli Bahrami * Given a value, and a pad alignment, return the number of bytes
179ba7866cdSAli Bahrami * required to pad the value to the next alignment boundary.
1809d6538abSab196087 */
181ba7866cdSAli Bahrami static size_t
pad(size_t n,size_t align)182ba7866cdSAli Bahrami pad(size_t n, size_t align)
1839d6538abSab196087 {
184ba7866cdSAli Bahrami size_t r;
1859d6538abSab196087
186ba7866cdSAli Bahrami r = n % align;
1879d6538abSab196087 if (r)
188ba7866cdSAli Bahrami r = align - r;
1899d6538abSab196087
1909d6538abSab196087 return (r);
1919d6538abSab196087 }
1929d6538abSab196087
1939d6538abSab196087 /*
194ba7866cdSAli Bahrami * If the current archive item is an ELF object, then ar(1) may have added
1959d6538abSab196087 * newline padding at the end in order to bring the following object
1969d6538abSab196087 * into PADSZ alignment within the file. This padding cannot be
197ba7866cdSAli Bahrami * distinguished from data using the information kept in the member header.
1989d6538abSab196087 * This routine examines the objects, using knowledge of
19930a4e2aaSab196087 * ELF and how our tools lay out objects to determine whether padding was
20030a4e2aaSab196087 * added to an archive item. If so, it adjusts the st_size and
20130a4e2aaSab196087 * st_padding fields of the file argument to reflect it.
20230a4e2aaSab196087 */
20330a4e2aaSab196087 static void
recover_padding(Elf * elf,ARFILE * file)20430a4e2aaSab196087 recover_padding(Elf *elf, ARFILE *file)
20530a4e2aaSab196087 {
206ba7866cdSAli Bahrami size_t extent;
207ba7866cdSAli Bahrami size_t padding;
208*f0a0736fSRichard Lowe size_t shnum;
20930a4e2aaSab196087 GElf_Ehdr ehdr;
21030a4e2aaSab196087
21130a4e2aaSab196087
21230a4e2aaSab196087 /* ar(1) only pads objects, so bail if not looking at one */
21330a4e2aaSab196087 if (gelf_getclass(elf) == ELFCLASSNONE)
21430a4e2aaSab196087 return;
21530a4e2aaSab196087
21630a4e2aaSab196087 /*
217d2d5cf7cSAli Bahrami * libelf always puts the section header array at the end
21830a4e2aaSab196087 * of the object, and all of our compilers and other tools
219d2d5cf7cSAli Bahrami * use libelf or follow this convention. So, it is extremely
22030a4e2aaSab196087 * likely that the section header array is at the end of this
22130a4e2aaSab196087 * object: Find the address at the end of the array and compare
2229d6538abSab196087 * it to the archive ar_size. If they are within PADSZ bytes, then
2239d6538abSab196087 * we've found the end, and the difference is padding (We assume
2249d6538abSab196087 * that no ELF section can fit into PADSZ bytes).
22530a4e2aaSab196087 */
226*f0a0736fSRichard Lowe if (elf_getshdrnum(elf, &shnum) == -1)
227*f0a0736fSRichard Lowe return;
228*f0a0736fSRichard Lowe
22930a4e2aaSab196087 extent = gelf_getehdr(elf, &ehdr)
230*f0a0736fSRichard Lowe ? (ehdr.e_shoff + (shnum * ehdr.e_shentsize)) : 0;
23130a4e2aaSab196087
232ba7866cdSAli Bahrami /*
233ba7866cdSAli Bahrami * If the extent exceeds the end of the archive member
234ba7866cdSAli Bahrami * (negative padding), then we don't know what is going on
235ba7866cdSAli Bahrami * and simply leave things alone.
236ba7866cdSAli Bahrami */
237ba7866cdSAli Bahrami if (extent > file->ar_size)
238ba7866cdSAli Bahrami return;
239ba7866cdSAli Bahrami
240ba7866cdSAli Bahrami padding = file->ar_size - extent;
241ba7866cdSAli Bahrami if (padding >= PADSZ) {
24230a4e2aaSab196087 /*
24330a4e2aaSab196087 * The section header array is not at the end of the object.
24430a4e2aaSab196087 * Traverse the section headers and look for the one with
24530a4e2aaSab196087 * the highest used address. If this address is within
2469d6538abSab196087 * PADSZ bytes of ar_size, then this is the end of the object.
24730a4e2aaSab196087 */
248ba7866cdSAli Bahrami Elf_Scn *scn = NULL;
24930a4e2aaSab196087
25030a4e2aaSab196087 do {
25130a4e2aaSab196087 scn = elf_nextscn(elf, scn);
25230a4e2aaSab196087 if (scn) {
25330a4e2aaSab196087 GElf_Shdr shdr;
25430a4e2aaSab196087
25530a4e2aaSab196087 if (gelf_getshdr(scn, &shdr)) {
256ba7866cdSAli Bahrami size_t t;
257ba7866cdSAli Bahrami
258ba7866cdSAli Bahrami t = shdr.sh_offset + shdr.sh_size;
25930a4e2aaSab196087 if (t > extent)
26030a4e2aaSab196087 extent = t;
26130a4e2aaSab196087 }
26230a4e2aaSab196087 }
26330a4e2aaSab196087 } while (scn);
264ba7866cdSAli Bahrami
265ba7866cdSAli Bahrami if (extent > file->ar_size)
266ba7866cdSAli Bahrami return;
267ba7866cdSAli Bahrami padding = file->ar_size - extent;
26830a4e2aaSab196087 }
26930a4e2aaSab196087
27030a4e2aaSab196087 /*
27130a4e2aaSab196087 * Now, test the padding. We only act on padding in the range
2729d6538abSab196087 * (0 < pad < PADSZ) (ar(1) will never add more than this). A pad
2739d6538abSab196087 * of 0 requires no action, and any other size above (PADSZ-1) means
27430a4e2aaSab196087 * that we don't understand the layout of this object, and as such,
27530a4e2aaSab196087 * cannot do anything.
27630a4e2aaSab196087 *
2779d6538abSab196087 * If the padding is in range, and the raw data for the
27830a4e2aaSab196087 * object is available, then we perform one additional sanity
27930a4e2aaSab196087 * check before moving forward: ar(1) always pads with newline
28030a4e2aaSab196087 * characters. If anything else is seen, it is not padding so
28130a4e2aaSab196087 * leave it alone.
28230a4e2aaSab196087 */
283ba7866cdSAli Bahrami if (padding < PADSZ) {
28430a4e2aaSab196087 if (file->ar_contents) {
285ba7866cdSAli Bahrami size_t cnt = padding;
28630a4e2aaSab196087 char *p = file->ar_contents + extent;
28730a4e2aaSab196087
28830a4e2aaSab196087 while (cnt--) {
28930a4e2aaSab196087 if (*p++ != '\n') { /* No padding */
29030a4e2aaSab196087 padding = 0;
29130a4e2aaSab196087 break;
29230a4e2aaSab196087 }
29330a4e2aaSab196087 }
29430a4e2aaSab196087 }
29530a4e2aaSab196087
29630a4e2aaSab196087 /* Remove the padding from the size */
29730a4e2aaSab196087 file->ar_size -= padding;
29830a4e2aaSab196087 file->ar_padding = padding;
29930a4e2aaSab196087 }
30030a4e2aaSab196087 }
30130a4e2aaSab196087
302ba7866cdSAli Bahrami /*
303ba7866cdSAli Bahrami * Each call to getfile() returns the next unread archive member
304ba7866cdSAli Bahrami * from the archive opened by getaf(). Returns NULL if no more
305ba7866cdSAli Bahrami * archive members are left.
306ba7866cdSAli Bahrami */
3077c478bd9Sstevel@tonic-gate ARFILE *
getfile(Cmd_info * cmd_info)3087c478bd9Sstevel@tonic-gate getfile(Cmd_info *cmd_info)
3097c478bd9Sstevel@tonic-gate {
310ba7866cdSAli Bahrami Elf_Arhdr *mem_header = NULL;
3117c478bd9Sstevel@tonic-gate ARFILE *file;
3127c478bd9Sstevel@tonic-gate char *tmp_rawname, *file_rawname;
3137c478bd9Sstevel@tonic-gate Elf *elf;
3147c478bd9Sstevel@tonic-gate char *arnam = cmd_info->arnam;
3157c478bd9Sstevel@tonic-gate int fd = cmd_info->afd;
3167c478bd9Sstevel@tonic-gate Elf *arf = cmd_info->arf;
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate if (fd == -1)
3197c478bd9Sstevel@tonic-gate return (NULL); /* the archive doesn't exist */
3207c478bd9Sstevel@tonic-gate
321ba7866cdSAli Bahrami while (mem_header == NULL) {
3227c478bd9Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, arf)) == 0)
323ba7866cdSAli Bahrami return (NULL); /* archive is empty or have hit end */
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate if ((mem_header = elf_getarhdr(elf)) == NULL) {
326ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_ELF_MALARCHIVE),
327ba7866cdSAli Bahrami arnam, EC_XWORD(elf_getbase(elf)), elf_errmsg(-1));
3287c478bd9Sstevel@tonic-gate exit(1);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate
331ba7866cdSAli Bahrami /* Ignore special members like the symbol and string tables */
332ba7866cdSAli Bahrami if (mem_header->ar_name[0] == '/') {
3337c478bd9Sstevel@tonic-gate (void) elf_next(elf);
3347c478bd9Sstevel@tonic-gate (void) elf_end(elf);
335ba7866cdSAli Bahrami mem_header = NULL;
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate * NOTE:
3417c478bd9Sstevel@tonic-gate * The mem_header->ar_name[] is set to a NULL string
3427c478bd9Sstevel@tonic-gate * if the archive member header has some error.
3437c478bd9Sstevel@tonic-gate * (See elf_getarhdr() man page.)
3447c478bd9Sstevel@tonic-gate * It is set to NULL for example, the ar command reads
3457c478bd9Sstevel@tonic-gate * the archive files created by SunOS 4.1 system.
3467c478bd9Sstevel@tonic-gate * See c block comment in cmd.c, "Incompatible Archive Header".
3477c478bd9Sstevel@tonic-gate */
3487c478bd9Sstevel@tonic-gate file = newfile();
3497c478bd9Sstevel@tonic-gate (void) strncpy(file->ar_name, mem_header->ar_name, SNAME);
3507c478bd9Sstevel@tonic-gate
351ba7866cdSAli Bahrami if ((file->ar_longname = malloc(strlen(mem_header->ar_name) + 1))
3527c478bd9Sstevel@tonic-gate == NULL) {
353ba7866cdSAli Bahrami int err = errno;
354ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
3557c478bd9Sstevel@tonic-gate exit(1);
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate (void) strcpy(file->ar_longname, mem_header->ar_name);
358ba7866cdSAli Bahrami if ((file->ar_rawname = malloc(strlen(mem_header->ar_rawname) + 1))
3597c478bd9Sstevel@tonic-gate == NULL) {
360ba7866cdSAli Bahrami int err = errno;
361ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
3627c478bd9Sstevel@tonic-gate exit(1);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate tmp_rawname = mem_header->ar_rawname;
3657c478bd9Sstevel@tonic-gate file_rawname = file->ar_rawname;
3667c478bd9Sstevel@tonic-gate while (!isspace(*tmp_rawname) &&
3677c478bd9Sstevel@tonic-gate ((*file_rawname = *tmp_rawname) != '\0')) {
3687c478bd9Sstevel@tonic-gate file_rawname++;
3697c478bd9Sstevel@tonic-gate tmp_rawname++;
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate if (!(*tmp_rawname == '\0'))
3727c478bd9Sstevel@tonic-gate *file_rawname = '\0';
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate file->ar_date = mem_header->ar_date;
3757c478bd9Sstevel@tonic-gate file->ar_uid = mem_header->ar_uid;
3767c478bd9Sstevel@tonic-gate file->ar_gid = mem_header->ar_gid;
3777c478bd9Sstevel@tonic-gate file->ar_mode = (unsigned long) mem_header->ar_mode;
3787c478bd9Sstevel@tonic-gate file->ar_size = mem_header->ar_size;
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate /* reverse logic */
381ba7866cdSAli Bahrami if ((cmd_info->opt_flgs & (t_FLAG | s_FLAG)) != t_FLAG) {
3827c478bd9Sstevel@tonic-gate size_t ptr;
3837c478bd9Sstevel@tonic-gate file->ar_flag = F_ELFRAW;
3847c478bd9Sstevel@tonic-gate if ((file->ar_contents = elf_rawfile(elf, &ptr))
3857c478bd9Sstevel@tonic-gate == NULL) {
3867c478bd9Sstevel@tonic-gate if (ptr != 0) {
387ba7866cdSAli Bahrami (void) fprintf(stderr,
388ba7866cdSAli Bahrami MSG_INTL(MSG_ELF_RAWFILE), elf_errmsg(-1));
3897c478bd9Sstevel@tonic-gate exit(1);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate file->ar_elf = elf;
3937c478bd9Sstevel@tonic-gate }
39430a4e2aaSab196087
39530a4e2aaSab196087 recover_padding(elf, file);
39630a4e2aaSab196087
3977c478bd9Sstevel@tonic-gate (void) elf_next(elf);
3987c478bd9Sstevel@tonic-gate return (file);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate
401ba7866cdSAli Bahrami /*
402ba7866cdSAli Bahrami * Allocate a new archive member descriptor and add it to the list.
403ba7866cdSAli Bahrami */
4047c478bd9Sstevel@tonic-gate ARFILE *
newfile(void)405d6555420Smike_s newfile(void)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate static ARFILE *buffer = NULL;
408ba7866cdSAli Bahrami static size_t count = 0;
4097c478bd9Sstevel@tonic-gate ARFILE *fileptr;
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate if (count == 0) {
4127c478bd9Sstevel@tonic-gate if ((buffer = (ARFILE *) calloc(CHUNK, sizeof (ARFILE)))
4137c478bd9Sstevel@tonic-gate == NULL) {
414ba7866cdSAli Bahrami int err = errno;
415ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_MALLOC),
416ba7866cdSAli Bahrami strerror(err));
4177c478bd9Sstevel@tonic-gate exit(1);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate count = CHUNK;
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate count--;
4227c478bd9Sstevel@tonic-gate fileptr = buffer++;
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate if (listhead)
4257c478bd9Sstevel@tonic-gate listend->ar_next = fileptr;
4267c478bd9Sstevel@tonic-gate else
4277c478bd9Sstevel@tonic-gate listhead = fileptr;
4287c478bd9Sstevel@tonic-gate listend = fileptr;
4297c478bd9Sstevel@tonic-gate return (fileptr);
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate static char *
trimslash(char * s)4337c478bd9Sstevel@tonic-gate trimslash(char *s)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate static char buf[SNAME];
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate (void) strncpy(buf, trim(s), SNAME - 2);
4387c478bd9Sstevel@tonic-gate buf[SNAME - 2] = '\0';
439ba7866cdSAli Bahrami return (strcat(buf, MSG_ORIG(MSG_STR_SLASH)));
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate char *
trim(char * s)4437c478bd9Sstevel@tonic-gate trim(char *s)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate char *p1, *p2;
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate for (p1 = s; *p1; p1++)
4487c478bd9Sstevel@tonic-gate ;
4497c478bd9Sstevel@tonic-gate while (p1 > s) {
4507c478bd9Sstevel@tonic-gate if (*--p1 != '/')
4517c478bd9Sstevel@tonic-gate break;
4527c478bd9Sstevel@tonic-gate *p1 = 0;
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate p2 = s;
4557c478bd9Sstevel@tonic-gate for (p1 = s; *p1; p1++)
4567c478bd9Sstevel@tonic-gate if (*p1 == '/')
4577c478bd9Sstevel@tonic-gate p2 = p1 + 1;
4587c478bd9Sstevel@tonic-gate return (p2);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate
4617c478bd9Sstevel@tonic-gate
462ba7866cdSAli Bahrami /*
463ba7866cdSAli Bahrami * Find all the global symbols exported by ELF archive members, and
464ba7866cdSAli Bahrami * build a list associating each one with the archive member that
465ba7866cdSAli Bahrami * provides it.
466ba7866cdSAli Bahrami *
467ba7866cdSAli Bahrami * exit:
468ba7866cdSAli Bahrami * *symlist is set to the list of symbols. If any ELF object was
469ba7866cdSAli Bahrami * found, *found_obj is set to TRUE (1). Returns the number of symbols
470ba7866cdSAli Bahrami * located.
471ba7866cdSAli Bahrami */
472ba7866cdSAli Bahrami static size_t
mksymtab(const char * arname,ARFILEP ** symlist,int * found_obj)473ba7866cdSAli Bahrami mksymtab(const char *arname, ARFILEP **symlist, int *found_obj)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate ARFILE *fptr;
476ba7866cdSAli Bahrami size_t mem_offset = 0;
4777c478bd9Sstevel@tonic-gate Elf *elf;
4787c478bd9Sstevel@tonic-gate Elf_Scn *scn;
4797c478bd9Sstevel@tonic-gate GElf_Ehdr ehdr;
4807c478bd9Sstevel@tonic-gate int newfd;
481ba7866cdSAli Bahrami size_t nsyms = 0;
4827c478bd9Sstevel@tonic-gate int class = 0;
4837c478bd9Sstevel@tonic-gate Elf_Data *data;
484ba7866cdSAli Bahrami size_t num_errs = 0;
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate newfd = 0;
4877c478bd9Sstevel@tonic-gate for (fptr = listhead; fptr; fptr = fptr->ar_next) {
4887c478bd9Sstevel@tonic-gate /* determine if file is coming from the archive or not */
489ba7866cdSAli Bahrami if ((fptr->ar_elf != NULL) && (fptr->ar_pathname == NULL)) {
4907c478bd9Sstevel@tonic-gate /*
4917c478bd9Sstevel@tonic-gate * I can use the saved elf descriptor.
4927c478bd9Sstevel@tonic-gate */
4937c478bd9Sstevel@tonic-gate elf = fptr->ar_elf;
494ba7866cdSAli Bahrami } else if ((fptr->ar_elf == NULL) &&
4957c478bd9Sstevel@tonic-gate (fptr->ar_pathname != NULL)) {
496ba7866cdSAli Bahrami #ifdef _LP64
497ba7866cdSAli Bahrami /*
498ba7866cdSAli Bahrami * The archive member header ar_size field is 10
499ba7866cdSAli Bahrami * decimal digits, sufficient to represent a 32-bit
500ba7866cdSAli Bahrami * value, but not a 64-bit one. Hence, we reject
501ba7866cdSAli Bahrami * attempts to insert a member larger than 4GB.
502ba7866cdSAli Bahrami *
503ba7866cdSAli Bahrami * One obvious way to extend the format without altering
504ba7866cdSAli Bahrami * the ar_hdr struct is to use the same mechanism used
505ba7866cdSAli Bahrami * for ar_name: Put the size string into the long name
506ba7866cdSAli Bahrami * string table and write a string /xxx into ar_size,
507ba7866cdSAli Bahrami * where xxx is the string table offset.
508ba7866cdSAli Bahrami *
509ba7866cdSAli Bahrami * At the time of this writing (June 2010), the largest
510ba7866cdSAli Bahrami * relocatable objects are measured in 10s or 100s
511ba7866cdSAli Bahrami * of megabytes, so we still have many years to go
512ba7866cdSAli Bahrami * before this becomes limiting. By that time, it may
513ba7866cdSAli Bahrami * turn out that a completely new archive format is
514ba7866cdSAli Bahrami * a better solution, as the current format has many
515ba7866cdSAli Bahrami * warts and inefficiencies. In the meantime, we
516ba7866cdSAli Bahrami * won't burden the current implementation with support
517ba7866cdSAli Bahrami * for a bandaid feature that will have little use.
518ba7866cdSAli Bahrami */
519ba7866cdSAli Bahrami if (fptr->ar_size > 0xffffffff) {
520ba7866cdSAli Bahrami (void) fprintf(stderr,
521ba7866cdSAli Bahrami MSG_INTL(MSG_ERR_MEMBER4G),
522ba7866cdSAli Bahrami fptr->ar_pathname);
523ba7866cdSAli Bahrami num_errs++;
524ba7866cdSAli Bahrami continue;
525ba7866cdSAli Bahrami }
526ba7866cdSAli Bahrami #endif
5277c478bd9Sstevel@tonic-gate if ((newfd =
5287c478bd9Sstevel@tonic-gate open(fptr->ar_pathname, O_RDONLY)) == -1) {
529ba7866cdSAli Bahrami int err = errno;
530ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
531ba7866cdSAli Bahrami fptr->ar_pathname, strerror(err));
5327c478bd9Sstevel@tonic-gate num_errs++;
5337c478bd9Sstevel@tonic-gate continue;
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate if ((elf = elf_begin(newfd,
537d2d5cf7cSAli Bahrami ELF_C_READ, (Elf *)0)) == 0) {
538ba7866cdSAli Bahrami (void) fprintf(stderr,
539ba7866cdSAli Bahrami MSG_INTL(MSG_ELF_BEGIN_FILE),
540ba7866cdSAli Bahrami fptr->ar_pathname, elf_errmsg(-1));
5417c478bd9Sstevel@tonic-gate (void) close(newfd);
5427c478bd9Sstevel@tonic-gate newfd = 0;
5437c478bd9Sstevel@tonic-gate num_errs++;
5447c478bd9Sstevel@tonic-gate continue;
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate if (elf_kind(elf) == ELF_K_AR) {
5477c478bd9Sstevel@tonic-gate if (newfd) {
5487c478bd9Sstevel@tonic-gate (void) close(newfd);
5497c478bd9Sstevel@tonic-gate newfd = 0;
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate (void) elf_end(elf);
5527c478bd9Sstevel@tonic-gate continue;
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate } else {
555ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_INTERNAL_01));
5567c478bd9Sstevel@tonic-gate exit(1);
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) != 0) {
559*f0a0736fSRichard Lowe size_t shstrndx = 0;
5607c478bd9Sstevel@tonic-gate if ((class = gelf_getclass(elf)) == ELFCLASS64) {
5617c478bd9Sstevel@tonic-gate fptr->ar_flag |= F_CLASS64;
5627c478bd9Sstevel@tonic-gate } else if (class == ELFCLASS32)
5637c478bd9Sstevel@tonic-gate fptr->ar_flag |= F_CLASS32;
564*f0a0736fSRichard Lowe
565*f0a0736fSRichard Lowe if (elf_getshdrstrndx(elf, &shstrndx) == -1) {
566*f0a0736fSRichard Lowe if (fptr->ar_pathname != NULL) {
567*f0a0736fSRichard Lowe (void) fprintf(stderr,
568*f0a0736fSRichard Lowe MSG_INTL(MSG_ELF_GETSHSTRNDX_FILE),
569*f0a0736fSRichard Lowe fptr->ar_pathname, elf_errmsg(-1));
570*f0a0736fSRichard Lowe } else {
571*f0a0736fSRichard Lowe (void) fprintf(stderr,
572*f0a0736fSRichard Lowe MSG_INTL(MSG_ELF_GETSHSTRNDX_AR),
573*f0a0736fSRichard Lowe arname, fptr->ar_longname,
574*f0a0736fSRichard Lowe elf_errmsg(-1));
575*f0a0736fSRichard Lowe }
576*f0a0736fSRichard Lowe num_errs++;
577*f0a0736fSRichard Lowe if (newfd) {
578*f0a0736fSRichard Lowe (void) close(newfd);
579*f0a0736fSRichard Lowe newfd = 0;
580*f0a0736fSRichard Lowe }
581*f0a0736fSRichard Lowe (void) elf_end(elf);
582*f0a0736fSRichard Lowe continue;
583*f0a0736fSRichard Lowe }
584*f0a0736fSRichard Lowe
585*f0a0736fSRichard Lowe scn = elf_getscn(elf, shstrndx);
5867c478bd9Sstevel@tonic-gate if (scn == NULL) {
5877c478bd9Sstevel@tonic-gate if (fptr->ar_pathname != NULL)
588ba7866cdSAli Bahrami (void) fprintf(stderr,
589ba7866cdSAli Bahrami MSG_INTL(MSG_ELF_GETSCN_FILE),
590ba7866cdSAli Bahrami fptr->ar_pathname, elf_errmsg(-1));
5917c478bd9Sstevel@tonic-gate else
592ba7866cdSAli Bahrami (void) fprintf(stderr,
593ba7866cdSAli Bahrami MSG_INTL(MSG_ELF_GETSCN_AR),
594ba7866cdSAli Bahrami arname, fptr->ar_longname,
595ba7866cdSAli Bahrami elf_errmsg(-1));
5967c478bd9Sstevel@tonic-gate num_errs++;
5977c478bd9Sstevel@tonic-gate if (newfd) {
5987c478bd9Sstevel@tonic-gate (void) close(newfd);
5997c478bd9Sstevel@tonic-gate newfd = 0;
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate (void) elf_end(elf);
6027c478bd9Sstevel@tonic-gate continue;
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate data = 0;
6067c478bd9Sstevel@tonic-gate data = elf_getdata(scn, data);
6077c478bd9Sstevel@tonic-gate if (data == NULL) {
6087c478bd9Sstevel@tonic-gate if (fptr->ar_pathname != NULL)
609ba7866cdSAli Bahrami (void) fprintf(stderr,
610ba7866cdSAli Bahrami MSG_INTL(MSG_ELF_GETDATA_FILE),
611ba7866cdSAli Bahrami fptr->ar_pathname, elf_errmsg(-1));
6127c478bd9Sstevel@tonic-gate else
613ba7866cdSAli Bahrami (void) fprintf(stderr,
614ba7866cdSAli Bahrami MSG_INTL(MSG_ELF_GETDATA_AR),
615ba7866cdSAli Bahrami arname, fptr->ar_longname,
616ba7866cdSAli Bahrami elf_errmsg(-1));
6177c478bd9Sstevel@tonic-gate num_errs++;
6187c478bd9Sstevel@tonic-gate if (newfd) {
6197c478bd9Sstevel@tonic-gate (void) close(newfd);
6207c478bd9Sstevel@tonic-gate newfd = 0;
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate (void) elf_end(elf);
6237c478bd9Sstevel@tonic-gate continue;
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate if (data->d_size == 0) {
6267c478bd9Sstevel@tonic-gate if (fptr->ar_pathname != NULL)
627ba7866cdSAli Bahrami (void) fprintf(stderr,
628ba7866cdSAli Bahrami MSG_INTL(MSG_W_ELF_NODATA_FILE),
6297c478bd9Sstevel@tonic-gate fptr->ar_pathname);
6307c478bd9Sstevel@tonic-gate else
631ba7866cdSAli Bahrami (void) fprintf(stderr,
632ba7866cdSAli Bahrami MSG_INTL(MSG_W_ELF_NODATA_AR),
633ba7866cdSAli Bahrami arname, fptr->ar_longname);
6347c478bd9Sstevel@tonic-gate if (newfd) {
6357c478bd9Sstevel@tonic-gate (void) close(newfd);
6367c478bd9Sstevel@tonic-gate newfd = 0;
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate (void) elf_end(elf);
6397c478bd9Sstevel@tonic-gate num_errs++;
6407c478bd9Sstevel@tonic-gate continue;
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate /* loop through sections to find symbol table */
6447c478bd9Sstevel@tonic-gate scn = 0;
6457c478bd9Sstevel@tonic-gate while ((scn = elf_nextscn(elf, scn)) != 0) {
6467c478bd9Sstevel@tonic-gate GElf_Shdr shdr;
6477c478bd9Sstevel@tonic-gate if (gelf_getshdr(scn, &shdr) == NULL) {
648ba7866cdSAli Bahrami /* BEGIN CSTYLED */
6497c478bd9Sstevel@tonic-gate if (fptr->ar_pathname != NULL)
650ba7866cdSAli Bahrami (void) fprintf(stderr,
651ba7866cdSAli Bahrami MSG_INTL(MSG_ELF_GETDATA_FILE),
652ba7866cdSAli Bahrami fptr->ar_pathname,
653d2d5cf7cSAli Bahrami elf_errmsg(-1));
654ba7866cdSAli Bahrami else
655ba7866cdSAli Bahrami (void) fprintf(stderr,
656ba7866cdSAli Bahrami MSG_INTL(MSG_ELF_GETDATA_AR),
657ba7866cdSAli Bahrami arname, fptr->ar_longname,
658ba7866cdSAli Bahrami elf_errmsg(-1));
659ba7866cdSAli Bahrami /* END CSTYLED */
6607c478bd9Sstevel@tonic-gate if (newfd) {
6617c478bd9Sstevel@tonic-gate (void) close(newfd);
6627c478bd9Sstevel@tonic-gate newfd = 0;
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate num_errs++;
6657c478bd9Sstevel@tonic-gate (void) elf_end(elf);
6667c478bd9Sstevel@tonic-gate continue;
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate *found_obj = 1;
669*f0a0736fSRichard Lowe if (shdr.sh_type == SHT_SYMTAB) {
670ba7866cdSAli Bahrami if (search_sym_tab(arname, fptr, elf,
671d2d5cf7cSAli Bahrami scn, &nsyms, symlist,
6727c478bd9Sstevel@tonic-gate &num_errs) == -1) {
6737c478bd9Sstevel@tonic-gate if (newfd) {
6747c478bd9Sstevel@tonic-gate (void) close(newfd);
6757c478bd9Sstevel@tonic-gate newfd = 0;
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate continue;
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate }
6807c478bd9Sstevel@tonic-gate }
681*f0a0736fSRichard Lowe }
6827c478bd9Sstevel@tonic-gate mem_offset += sizeof (struct ar_hdr) + fptr->ar_size;
6837c478bd9Sstevel@tonic-gate if (fptr->ar_size & 01)
6847c478bd9Sstevel@tonic-gate mem_offset++;
6857c478bd9Sstevel@tonic-gate (void) elf_end(elf);
6867c478bd9Sstevel@tonic-gate if (newfd) {
6877c478bd9Sstevel@tonic-gate (void) close(newfd);
6887c478bd9Sstevel@tonic-gate newfd = 0;
6897c478bd9Sstevel@tonic-gate }
690ba7866cdSAli Bahrami }
6917c478bd9Sstevel@tonic-gate if (num_errs)
6927c478bd9Sstevel@tonic-gate exit(1);
693ba7866cdSAli Bahrami
694ba7866cdSAli Bahrami if (found_obj) {
695ba7866cdSAli Bahrami if (nsyms == 0) {
696ba7866cdSAli Bahrami /*
697ba7866cdSAli Bahrami * It is possible, though rare, to have ELF objects
698ba7866cdSAli Bahrami * that do not export any global symbols. Presumably
699ba7866cdSAli Bahrami * such objects operate via their .init/.fini
700ba7866cdSAli Bahrami * sections. In this case, we produce an empty
701ba7866cdSAli Bahrami * symbol table, so that applications that rely
702ba7866cdSAli Bahrami * on a successful call to elf_getarsym() to determine
703ba7866cdSAli Bahrami * if ELF objects are present will succeed. To do this,
704ba7866cdSAli Bahrami * we require a small empty symbol string table.
705ba7866cdSAli Bahrami */
706ba7866cdSAli Bahrami strtbl_pad(&sym_strtbl, 4, '\0');
707ba7866cdSAli Bahrami } else {
708ba7866cdSAli Bahrami /*
709ba7866cdSAli Bahrami * Historical behavior is to pad string tables
710ba7866cdSAli Bahrami * to a multiple of 4.
711ba7866cdSAli Bahrami */
712ba7866cdSAli Bahrami strtbl_pad(&sym_strtbl, pad(sym_strtbl.used, 4), '\0');
713ba7866cdSAli Bahrami }
714ba7866cdSAli Bahrami
715ba7866cdSAli Bahrami }
716ba7866cdSAli Bahrami
7177c478bd9Sstevel@tonic-gate return (nsyms);
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate /*
721ba7866cdSAli Bahrami * Output a member header.
7227c478bd9Sstevel@tonic-gate */
723ba7866cdSAli Bahrami /*ARGSUSED*/
724ba7866cdSAli Bahrami static void
write_member_header(const char * filename,int fd,int is_elf,const char * name,time_t timestamp,uid_t uid,gid_t gid,mode_t mode,size_t size)725ba7866cdSAli Bahrami write_member_header(const char *filename, int fd, int is_elf,
726ba7866cdSAli Bahrami const char *name, time_t timestamp, uid_t uid, gid_t gid, mode_t mode,
727ba7866cdSAli Bahrami size_t size)
7287c478bd9Sstevel@tonic-gate {
729ba7866cdSAli Bahrami char buf[sizeof (struct ar_hdr) + 1];
730ba7866cdSAli Bahrami int len;
731ba7866cdSAli Bahrami
732ba7866cdSAli Bahrami len = snprintf(buf, sizeof (buf), MSG_ORIG(MSG_MH_FORMAT), name,
733ba7866cdSAli Bahrami EC_WORD(timestamp), EC_WORD(uid), EC_WORD(gid), EC_WORD(mode),
734ba7866cdSAli Bahrami EC_XWORD(size), ARFMAG);
7357c478bd9Sstevel@tonic-gate
7367c478bd9Sstevel@tonic-gate /*
737ba7866cdSAli Bahrami * If snprintf() reports that it needed more space than we gave
738ba7866cdSAli Bahrami * it, it means that the caller fed us a long name, which is a
739ba7866cdSAli Bahrami * fatal internal error.
7407c478bd9Sstevel@tonic-gate */
741ba7866cdSAli Bahrami if (len != sizeof (struct ar_hdr)) {
742ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_INTERNAL_02));
7437c478bd9Sstevel@tonic-gate exit(1);
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate
746ba7866cdSAli Bahrami arwrite(filename, fd, buf, len);
747ba7866cdSAli Bahrami
748ba7866cdSAli Bahrami /*
749ba7866cdSAli Bahrami * We inject inter-member padding to ensure that ELF object
750ba7866cdSAli Bahrami * member data is aligned on PADSZ. If this is a debug build,
751ba7866cdSAli Bahrami * verify that the computations were right.
752ba7866cdSAli Bahrami */
753ba7866cdSAli Bahrami assert(!is_elf || (pad(lseek(fd, 0, SEEK_CUR), PADSZ) == 0));
754ba7866cdSAli Bahrami }
755ba7866cdSAli Bahrami
756ba7866cdSAli Bahrami /*
757ba7866cdSAli Bahrami * Write the archive symbol table member to the output archive file.
758ba7866cdSAli Bahrami *
759ba7866cdSAli Bahrami * note:
760ba7866cdSAli Bahrami * sizeofmembers() must have been called to establish member offset
761ba7866cdSAli Bahrami * and padding values before writesymtab() is used.
762ba7866cdSAli Bahrami */
763ba7866cdSAli Bahrami static void
writesymtab(const char * filename,int fd,size_t nsyms,ARFILEP * symlist,size_t eltsize)764ba7866cdSAli Bahrami writesymtab(const char *filename, int fd, size_t nsyms, ARFILEP *symlist,
765ba7866cdSAli Bahrami size_t eltsize)
766ba7866cdSAli Bahrami {
767ba7866cdSAli Bahrami size_t i, j;
768ba7866cdSAli Bahrami ARFILEP *ptr;
769ba7866cdSAli Bahrami size_t tblsize;
770ba7866cdSAli Bahrami char *buf, *dst;
771ba7866cdSAli Bahrami int is64 = (eltsize == 8);
772ba7866cdSAli Bahrami
773ba7866cdSAli Bahrami /*
774ba7866cdSAli Bahrami * We require a buffer large enough to hold a symbol table count,
775ba7866cdSAli Bahrami * plus one offset for each symbol.
776ba7866cdSAli Bahrami */
777ba7866cdSAli Bahrami tblsize = (nsyms + 1) * eltsize;
778ba7866cdSAli Bahrami if ((buf = dst = malloc(tblsize)) == NULL) {
779ba7866cdSAli Bahrami int err = errno;
780ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
7817c478bd9Sstevel@tonic-gate exit(1);
7827c478bd9Sstevel@tonic-gate }
783ba7866cdSAli Bahrami
784ba7866cdSAli Bahrami write_member_header(filename, fd, 0,
785ba7866cdSAli Bahrami (is64 ? MSG_ORIG(MSG_STR_SYM64) : MSG_ORIG(MSG_STR_SLASH)),
786ba7866cdSAli Bahrami time(0), 0, 0, 0, tblsize + sym_strtbl.used);
787ba7866cdSAli Bahrami
788ba7866cdSAli Bahrami dst = is64 ? sputl64(nsyms, dst) : sputl32(nsyms, dst);
7897c478bd9Sstevel@tonic-gate
7907c478bd9Sstevel@tonic-gate for (i = 0, j = SYMCHUNK, ptr = symlist; i < nsyms; i++, j--, ptr++) {
7917c478bd9Sstevel@tonic-gate if (!j) {
7927c478bd9Sstevel@tonic-gate j = SYMCHUNK;
7937c478bd9Sstevel@tonic-gate ptr = (ARFILEP *)*ptr;
7947c478bd9Sstevel@tonic-gate }
795ba7866cdSAli Bahrami dst = is64 ? sputl64((*ptr)->ar_offset, dst) :
796ba7866cdSAli Bahrami sputl32((*ptr)->ar_offset, dst);
7977c478bd9Sstevel@tonic-gate }
798ba7866cdSAli Bahrami arwrite(filename, fd, buf, tblsize);
799ba7866cdSAli Bahrami free(buf);
800ba7866cdSAli Bahrami arwrite(filename, fd, sym_strtbl.base, sym_strtbl.used);
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate /*
804ba7866cdSAli Bahrami * Grow the size of the given string table so that there is room
805ba7866cdSAli Bahrami * for at least need bytes.
806ba7866cdSAli Bahrami *
807ba7866cdSAli Bahrami * entry:
808ba7866cdSAli Bahrami * strtbl - String table to grow
809ba7866cdSAli Bahrami * need - Amount of space required by caller
8107c478bd9Sstevel@tonic-gate */
811ba7866cdSAli Bahrami static void
strtbl_alloc(ARSTRTBL * strtbl,size_t need)812ba7866cdSAli Bahrami strtbl_alloc(ARSTRTBL *strtbl, size_t need)
813ba7866cdSAli Bahrami {
814ba7866cdSAli Bahrami #define STRTBL_INITSZ 8196
815ba7866cdSAli Bahrami
816ba7866cdSAli Bahrami /*
817ba7866cdSAli Bahrami * On 32-bit systems, we require a larger integer type in order
818ba7866cdSAli Bahrami * to avoid overflow and wraparound when doing our computations.
819ba7866cdSAli Bahrami */
820ba7866cdSAli Bahrami uint64_t need64 = need;
821ba7866cdSAli Bahrami uint64_t used64 = strtbl->used;
822ba7866cdSAli Bahrami uint64_t size64 = strtbl->size;
823ba7866cdSAli Bahrami uint64_t target = need64 + used64;
824ba7866cdSAli Bahrami
825ba7866cdSAli Bahrami int sys32, tbl32;
826ba7866cdSAli Bahrami
827ba7866cdSAli Bahrami if (target <= size64)
828ba7866cdSAli Bahrami return;
829ba7866cdSAli Bahrami
830ba7866cdSAli Bahrami /*
831ba7866cdSAli Bahrami * Detect 32-bit system. We might usually do this with the preprocessor,
832ba7866cdSAli Bahrami * but it can serve as a predicate in tests that also apply to 64-bit
833ba7866cdSAli Bahrami * systems.
834ba7866cdSAli Bahrami */
835ba7866cdSAli Bahrami sys32 = (sizeof (size_t) == 4);
836ba7866cdSAli Bahrami
837ba7866cdSAli Bahrami /*
838ba7866cdSAli Bahrami * The symbol string table can be larger than 32-bits on a 64-bit
839ba7866cdSAli Bahrami * system. However, the long name table must stay below that limit.
840ba7866cdSAli Bahrami * The reason for this is that there is not enough room in the ar_name
841ba7866cdSAli Bahrami * field of the member header to represent 64-bit offsets.
842ba7866cdSAli Bahrami */
843ba7866cdSAli Bahrami tbl32 = (strtbl == &long_strtbl);
844ba7866cdSAli Bahrami
845ba7866cdSAli Bahrami /*
846ba7866cdSAli Bahrami * If request is larger than 4GB and we can't do it because we
847ba7866cdSAli Bahrami * are a 32-bit program, or because the table is format limited,
848ba7866cdSAli Bahrami * we can go no further.
849ba7866cdSAli Bahrami */
850ba7866cdSAli Bahrami if ((target > 0xffffffff) && (sys32 || tbl32))
851ba7866cdSAli Bahrami goto limit_fail;
852ba7866cdSAli Bahrami
853ba7866cdSAli Bahrami /* Default starting size */
854ba7866cdSAli Bahrami if (strtbl->base == NULL)
855ba7866cdSAli Bahrami size64 = STRTBL_INITSZ;
856ba7866cdSAli Bahrami
857ba7866cdSAli Bahrami /*
858ba7866cdSAli Bahrami * Our strategy is to double the size until we find a size that
859ba7866cdSAli Bahrami * exceeds the request. However, if this table cannot exceed 4GB,
860ba7866cdSAli Bahrami * then once we exceed 2GB, we switch to a strategy of taking the
861ba7866cdSAli Bahrami * current request and rounding it up to STRTBL_INITSZ.
862ba7866cdSAli Bahrami */
863ba7866cdSAli Bahrami while (target > size64) {
864ba7866cdSAli Bahrami if ((target > 0x7fffffff) && (sys32 || tbl32)) {
865ba7866cdSAli Bahrami size64 = ((target + STRTBL_INITSZ) / STRTBL_INITSZ) *
866ba7866cdSAli Bahrami STRTBL_INITSZ;
867ba7866cdSAli Bahrami
868ba7866cdSAli Bahrami /*
869ba7866cdSAli Bahrami * If we are so close to the line that this small
870ba7866cdSAli Bahrami * increment exceeds 4GB, give it up.
871ba7866cdSAli Bahrami */
872ba7866cdSAli Bahrami if ((size64 > 0xffffffff) && (sys32 || tbl32))
873ba7866cdSAli Bahrami goto limit_fail;
874ba7866cdSAli Bahrami
875ba7866cdSAli Bahrami break;
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate
878ba7866cdSAli Bahrami size64 *= 2;
8797c478bd9Sstevel@tonic-gate }
8807c478bd9Sstevel@tonic-gate
881ba7866cdSAli Bahrami strtbl->base = realloc(strtbl->base, size64);
882ba7866cdSAli Bahrami if (strtbl->base == NULL) {
883ba7866cdSAli Bahrami int err = errno;
884ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
885ba7866cdSAli Bahrami exit(1);
886ba7866cdSAli Bahrami }
887ba7866cdSAli Bahrami strtbl->size = (size_t)size64;
888ba7866cdSAli Bahrami return;
889ba7866cdSAli Bahrami
890ba7866cdSAli Bahrami limit_fail:
891ba7866cdSAli Bahrami /*
892ba7866cdSAli Bahrami * Control comes here if we are unable to allocate more than 4GB of
893ba7866cdSAli Bahrami * memory for the string table due to one of the following reasons:
894ba7866cdSAli Bahrami *
895ba7866cdSAli Bahrami * - A 32-bit process is attempting to be larger than 4GB
896ba7866cdSAli Bahrami *
897ba7866cdSAli Bahrami * - A 64-bit process is attempting to grow the long names string
898ba7866cdSAli Bahrami * table beyond the ar format limit of 32-bits.
899ba7866cdSAli Bahrami */
900ba7866cdSAli Bahrami if (sys32)
901ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(ENOMEM));
902ba7866cdSAli Bahrami else
903ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_ERR_LONGSTRTBLSZ));
904ba7866cdSAli Bahrami exit(1);
905ba7866cdSAli Bahrami
906ba7866cdSAli Bahrami #undef STRTBL_INITSZ
907ba7866cdSAli Bahrami }
908ba7866cdSAli Bahrami
909ba7866cdSAli Bahrami /*
910ba7866cdSAli Bahrami * Add the specified number of pad characters to the end of the
911ba7866cdSAli Bahrami * given string table.
912ba7866cdSAli Bahrami *
913ba7866cdSAli Bahrami * entry:
914ba7866cdSAli Bahrami * strtbl - String table to pad
915ba7866cdSAli Bahrami * n - # of pad characters to add
916ba7866cdSAli Bahrami * ch - Pad character to use
917ba7866cdSAli Bahrami */
918ba7866cdSAli Bahrami static void
strtbl_pad(ARSTRTBL * strtbl,size_t n,int ch)919ba7866cdSAli Bahrami strtbl_pad(ARSTRTBL *strtbl, size_t n, int ch)
920ba7866cdSAli Bahrami {
921ba7866cdSAli Bahrami if (n == 0)
922ba7866cdSAli Bahrami return;
923ba7866cdSAli Bahrami
924ba7866cdSAli Bahrami if ((n + strtbl->used) > strtbl->size)
925ba7866cdSAli Bahrami strtbl_alloc(strtbl, n);
926ba7866cdSAli Bahrami
927ba7866cdSAli Bahrami while (n--)
928ba7866cdSAli Bahrami strtbl->base[strtbl->used++] = ch;
929ba7866cdSAli Bahrami }
930ba7866cdSAli Bahrami
931ba7866cdSAli Bahrami /*
932ba7866cdSAli Bahrami * Enter a symbol name into the symbol string table.
933ba7866cdSAli Bahrami */
9347c478bd9Sstevel@tonic-gate static void
savename(char * symbol)9357c478bd9Sstevel@tonic-gate savename(char *symbol)
9367c478bd9Sstevel@tonic-gate {
937ba7866cdSAli Bahrami size_t need;
9387c478bd9Sstevel@tonic-gate
939ba7866cdSAli Bahrami need = strlen(symbol) + 1;
940ba7866cdSAli Bahrami if ((need + sym_strtbl.used) > sym_strtbl.size)
941ba7866cdSAli Bahrami strtbl_alloc(&sym_strtbl, need);
942ba7866cdSAli Bahrami
943ba7866cdSAli Bahrami (void) strcpy(sym_strtbl.base + sym_strtbl.used, symbol);
944ba7866cdSAli Bahrami sym_strtbl.used += need;
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate
9477c478bd9Sstevel@tonic-gate /*
948ba7866cdSAli Bahrami * Prepare an archive member with a long (>15 characters) name for
949ba7866cdSAli Bahrami * the output archive.
950ba7866cdSAli Bahrami *
951ba7866cdSAli Bahrami * entry:
952ba7866cdSAli Bahrami * fptr - pointer to archive member with long name
953ba7866cdSAli Bahrami *
954ba7866cdSAli Bahrami * exit:
955ba7866cdSAli Bahrami * The long name is entered into the long name string table,
956ba7866cdSAli Bahrami * and fptr->ar_name has been replaced with the special /xxx
957ba7866cdSAli Bahrami * name used to indicate that the real name is in the string table
958ba7866cdSAli Bahrami * at offset xxx.
9597c478bd9Sstevel@tonic-gate */
9607c478bd9Sstevel@tonic-gate static void
savelongname(ARFILE * fptr)961ba7866cdSAli Bahrami savelongname(ARFILE *fptr)
9627c478bd9Sstevel@tonic-gate {
963ba7866cdSAli Bahrami size_t len, need;
964ba7866cdSAli Bahrami char *p;
9657c478bd9Sstevel@tonic-gate
966ba7866cdSAli Bahrami /* Size of new item to add */
967ba7866cdSAli Bahrami len = strlen(fptr->ar_longname);
968ba7866cdSAli Bahrami need = len + 2;
9697c478bd9Sstevel@tonic-gate
970ba7866cdSAli Bahrami /* Ensure there's room */
971ba7866cdSAli Bahrami if ((need + long_strtbl.used) > long_strtbl.size)
972ba7866cdSAli Bahrami strtbl_alloc(&long_strtbl, need);
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate /*
975ba7866cdSAli Bahrami * Generate the index string to be written into the member header
976ba7866cdSAli Bahrami *
977ba7866cdSAli Bahrami * This will not overflow the ar_name field because that field is
978ba7866cdSAli Bahrami * 16 characters in size, and a 32-bit unsigned value can be formatted
979ba7866cdSAli Bahrami * in 10 characters. Allowing a character for the leading '/', and one
980ba7866cdSAli Bahrami * for the NULL termination, that leaves us with 4 extra spaces.
9817c478bd9Sstevel@tonic-gate */
982ba7866cdSAli Bahrami (void) snprintf(fptr->ar_name, sizeof (fptr->ar_name),
983ba7866cdSAli Bahrami MSG_ORIG(MSG_FMT_LLINT), EC_XWORD(long_strtbl.used));
984ba7866cdSAli Bahrami
985ba7866cdSAli Bahrami /*
986ba7866cdSAli Bahrami * Enter long name into reserved spot, terminated with a slash
987ba7866cdSAli Bahrami * and a newline character.
988ba7866cdSAli Bahrami */
989ba7866cdSAli Bahrami p = long_strtbl.base + long_strtbl.used;
990ba7866cdSAli Bahrami long_strtbl.used += need;
991ba7866cdSAli Bahrami (void) strcpy(p, fptr->ar_longname);
992ba7866cdSAli Bahrami p += len;
9937c478bd9Sstevel@tonic-gate *p++ = '/';
9947c478bd9Sstevel@tonic-gate *p++ = '\n';
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate
997ba7866cdSAli Bahrami /*
998ba7866cdSAli Bahrami * Determine if the archive we're about to write will exceed the
999ba7866cdSAli Bahrami * 32-bit limit of 4GB.
1000ba7866cdSAli Bahrami *
1001ba7866cdSAli Bahrami * entry:
1002ba7866cdSAli Bahrami * mksymtab() and mklong_tab() have been called to set up
1003ba7866cdSAli Bahrami * the string tables.
1004ba7866cdSAli Bahrami *
1005ba7866cdSAli Bahrami * exit:
1006ba7866cdSAli Bahrami * Returns TRUE (1) if the 64-bit symbol table is needed, and
1007ba7866cdSAli Bahrami * FALSE (0) otherwise.
1008ba7866cdSAli Bahrami *
1009ba7866cdSAli Bahrami */
1010ba7866cdSAli Bahrami static int
require64(size_t nsyms,int found_obj,size_t longnames)1011ba7866cdSAli Bahrami require64(size_t nsyms, int found_obj, size_t longnames)
1012ba7866cdSAli Bahrami {
1013ba7866cdSAli Bahrami ARFILE *fptr;
1014ba7866cdSAli Bahrami uint64_t size;
1015ba7866cdSAli Bahrami
1016ba7866cdSAli Bahrami /*
1017ba7866cdSAli Bahrami * If there are more than 4GB symbols, we have to use
1018ba7866cdSAli Bahrami * the 64-bit form. Note that longnames cannot exceed 4GB
1019ba7866cdSAli Bahrami * because that symbol table is limited to a length of 4GB by
1020ba7866cdSAli Bahrami * the archive format.
1021ba7866cdSAli Bahrami */
1022ba7866cdSAli Bahrami if (nsyms > 0xffffffff)
1023ba7866cdSAli Bahrami return (1);
1024ba7866cdSAli Bahrami
1025ba7866cdSAli Bahrami /*
1026ba7866cdSAli Bahrami * Make a worst case estimate for the size of the resulting
1027ba7866cdSAli Bahrami * archive by assuming full padding between members.
1028ba7866cdSAli Bahrami */
1029ba7866cdSAli Bahrami size = SARMAG;
1030ba7866cdSAli Bahrami if (longnames)
1031ba7866cdSAli Bahrami size += sizeof (struct ar_hdr) + long_strtbl.used + PADSZ;
1032ba7866cdSAli Bahrami
1033ba7866cdSAli Bahrami if (found_obj)
1034ba7866cdSAli Bahrami size += sizeof_symtbl(nsyms, found_obj, 4) + PADSZ;
1035ba7866cdSAli Bahrami
1036ba7866cdSAli Bahrami if (size > 0xffffffff)
1037ba7866cdSAli Bahrami return (1);
1038ba7866cdSAli Bahrami
1039ba7866cdSAli Bahrami for (fptr = listhead; fptr; fptr = fptr->ar_next) {
1040ba7866cdSAli Bahrami size += sizeof (struct ar_hdr) + fptr->ar_size + PADSZ;
1041ba7866cdSAli Bahrami
1042ba7866cdSAli Bahrami if (size > 0xffffffff)
1043ba7866cdSAli Bahrami return (1);
1044ba7866cdSAli Bahrami }
1045ba7866cdSAli Bahrami
1046ba7866cdSAli Bahrami /* 32-bit symbol table will suffice */
1047ba7866cdSAli Bahrami return (0);
1048ba7866cdSAli Bahrami }
1049ba7866cdSAli Bahrami
1050ba7866cdSAli Bahrami void
writefile(Cmd_info * cmd_info)10517c478bd9Sstevel@tonic-gate writefile(Cmd_info *cmd_info)
10527c478bd9Sstevel@tonic-gate {
10537c478bd9Sstevel@tonic-gate ARFILE *fptr;
10547c478bd9Sstevel@tonic-gate ARFILEP *symlist = 0;
1055ba7866cdSAli Bahrami size_t longnames;
1056ba7866cdSAli Bahrami size_t nsyms;
10577c478bd9Sstevel@tonic-gate int new_archive = 0;
10587c478bd9Sstevel@tonic-gate char *name = cmd_info->arnam;
1059ba7866cdSAli Bahrami size_t arsize; /* Size of magic # and special members */
1060ba7866cdSAli Bahrami size_t symtbl_eltsize = 4;
10617c478bd9Sstevel@tonic-gate int found_obj = 0;
1062ba7866cdSAli Bahrami int fd;
1063ba7866cdSAli Bahrami off_t off;
1064ba7866cdSAli Bahrami struct stat stbuf, ar_stbuf;
1065ba7866cdSAli Bahrami char pad_bytes[PADSZ];
1066ba7866cdSAli Bahrami size_t pad_cnt;
1067ba7866cdSAli Bahrami int is_elf;
10687c478bd9Sstevel@tonic-gate
1069ba7866cdSAli Bahrami /*
1070ba7866cdSAli Bahrami * Gather the list of symbols and associate each one to the
1071ba7866cdSAli Bahrami * ARFILE descriptor of the object it belongs to. At the same
1072ba7866cdSAli Bahrami * time, tag each ELF object with the appropriate F_CLASSxx
1073ba7866cdSAli Bahrami * flag.
1074ba7866cdSAli Bahrami */
1075ba7866cdSAli Bahrami nsyms = mksymtab(name, &symlist, &found_obj);
10767c478bd9Sstevel@tonic-gate
1077ba7866cdSAli Bahrami /* Generate the string table for long member names */
1078ba7866cdSAli Bahrami longnames = mklong_tab();
10797c478bd9Sstevel@tonic-gate
1080ba7866cdSAli Bahrami /*
1081ba7866cdSAli Bahrami * Will this archive exceed 4GB? If we're a 32-bit process, we can't
1082ba7866cdSAli Bahrami * do it. If we're a 64-bit process, then we'll have to use a
1083ba7866cdSAli Bahrami * 64-bit symbol table.
1084ba7866cdSAli Bahrami */
1085ba7866cdSAli Bahrami if (require64(nsyms, found_obj, longnames)) {
1086ba7866cdSAli Bahrami #ifdef _LP64
1087ba7866cdSAli Bahrami symtbl_eltsize = 8;
1088ba7866cdSAli Bahrami #else
1089ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_TOOBIG4G));
1090ba7866cdSAli Bahrami exit(1);
1091ba7866cdSAli Bahrami #endif
1092ba7866cdSAli Bahrami }
10937c478bd9Sstevel@tonic-gate
1094ba7866cdSAli Bahrami /*
1095ba7866cdSAli Bahrami * If the user requested it, use the 64-bit symbol table even if
1096ba7866cdSAli Bahrami * a 32-bit one would suffice. 32-bit tables are more portable and
1097ba7866cdSAli Bahrami * take up less room, so this feature is primarily for testing.
1098ba7866cdSAli Bahrami */
1099ba7866cdSAli Bahrami if (cmd_info->opt_flgs & S_FLAG)
1100ba7866cdSAli Bahrami symtbl_eltsize = 8;
1101ba7866cdSAli Bahrami
1102ba7866cdSAli Bahrami /*
1103ba7866cdSAli Bahrami * If the first non-special archive member is an ELF object, then we
1104ba7866cdSAli Bahrami * need to arrange for its data to have an alignment of PADSZ. The
1105ba7866cdSAli Bahrami * preceeding special member will be the symbol table, or the long
1106ba7866cdSAli Bahrami * name string table. We pad the string table that precedes the
1107ba7866cdSAli Bahrami * ELF member in order to achive the desired alignment.
1108ba7866cdSAli Bahrami */
1109ba7866cdSAli Bahrami is_elf = listhead && (listhead->ar_flag & (F_CLASS32 | F_CLASS64));
1110ba7866cdSAli Bahrami arsize = SARMAG;
1111ba7866cdSAli Bahrami if (found_obj) {
1112ba7866cdSAli Bahrami arsize += sizeof_symtbl(nsyms, found_obj, symtbl_eltsize);
1113ba7866cdSAli Bahrami if (is_elf && (longnames == 0)) {
1114ba7866cdSAli Bahrami pad_cnt = pad(arsize + sizeof (struct ar_hdr), PADSZ);
1115ba7866cdSAli Bahrami strtbl_pad(&sym_strtbl, pad_cnt, '\0');
1116ba7866cdSAli Bahrami arsize += pad_cnt;
1117ba7866cdSAli Bahrami }
1118ba7866cdSAli Bahrami }
1119ba7866cdSAli Bahrami if (longnames > 0) {
1120ba7866cdSAli Bahrami arsize += sizeof (struct ar_hdr) + long_strtbl.used;
1121ba7866cdSAli Bahrami if (is_elf) {
1122ba7866cdSAli Bahrami pad_cnt = pad(arsize + sizeof (struct ar_hdr), PADSZ);
1123ba7866cdSAli Bahrami strtbl_pad(&long_strtbl, pad_cnt, '\0');
1124ba7866cdSAli Bahrami arsize += pad_cnt;
1125ba7866cdSAli Bahrami }
1126ba7866cdSAli Bahrami }
1127ba7866cdSAli Bahrami
1128ba7866cdSAli Bahrami /*
1129ba7866cdSAli Bahrami * For each user visible (non-special) archive member, determine
1130ba7866cdSAli Bahrami * the header offset, and the size of any required padding.
1131ba7866cdSAli Bahrami */
1132ba7866cdSAli Bahrami (void) sizeofmembers(arsize);
1133ba7866cdSAli Bahrami
1134ba7866cdSAli Bahrami /*
1135ba7866cdSAli Bahrami * Is this a new archive, or are we updating an existing one?
1136ba7866cdSAli Bahrami *
1137ba7866cdSAli Bahrami * A subtlety here is that POSIX says we are not supposed
1138ba7866cdSAli Bahrami * to replace a non-writable file. The only 100% reliable test
1139ba7866cdSAli Bahrami * against this is to open the file for non-destructive
1140ba7866cdSAli Bahrami * write access. If the open succeeds, we are clear to
1141ba7866cdSAli Bahrami * replace it, and if not, then the error generated is
1142ba7866cdSAli Bahrami * the error we need to report.
1143ba7866cdSAli Bahrami */
1144ba7866cdSAli Bahrami if ((fd = open(name, O_RDWR)) < 0) {
1145ba7866cdSAli Bahrami int err = errno;
1146ba7866cdSAli Bahrami
1147ba7866cdSAli Bahrami if (err != ENOENT) {
1148ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
1149ba7866cdSAli Bahrami name, strerror(err));
1150ba7866cdSAli Bahrami exit(1);
1151ba7866cdSAli Bahrami }
11527c478bd9Sstevel@tonic-gate new_archive = 1;
1153ba7866cdSAli Bahrami if ((cmd_info->opt_flgs & c_FLAG) == 0) {
1154ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_BER_MES_CREATE),
1155ba7866cdSAli Bahrami cmd_info->arnam);
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate } else {
1158ba7866cdSAli Bahrami /* Capture mode and owner information to apply to replacement */
1159ba7866cdSAli Bahrami if (fstat(fd, &ar_stbuf) < 0) {
1160ba7866cdSAli Bahrami int err = errno;
1161ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_STAT),
1162ba7866cdSAli Bahrami name, strerror(err));
1163ba7866cdSAli Bahrami (void) close(fd);
1164ba7866cdSAli Bahrami exit(1);
11657c478bd9Sstevel@tonic-gate }
1166ba7866cdSAli Bahrami (void) close(fd);
1167ba7866cdSAli Bahrami new_archive = 0;
11687c478bd9Sstevel@tonic-gate }
11697c478bd9Sstevel@tonic-gate
11707c478bd9Sstevel@tonic-gate
1171ba7866cdSAli Bahrami /*
1172ba7866cdSAli Bahrami * Register exit handler function to clean up after us if we exit
1173ba7866cdSAli Bahrami * before completing the new archive. atexit() is defined as
1174ba7866cdSAli Bahrami * only being able to fail due to memory exhaustion.
1175ba7866cdSAli Bahrami */
1176ba7866cdSAli Bahrami if (atexit(exit_cleanup) != 0) {
1177ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(ENOMEM));
1178ba7866cdSAli Bahrami exit(1);
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate
1181ba7866cdSAli Bahrami /*
1182ba7866cdSAli Bahrami * If a new archive, create it in place. If updating an archive,
1183ba7866cdSAli Bahrami * create the replacement under a temporary name and then rename it
1184ba7866cdSAli Bahrami * into place.
1185ba7866cdSAli Bahrami */
1186ba7866cdSAli Bahrami ar_outfile.path = new_archive ? name : make_tmpname(name);
1187ba7866cdSAli Bahrami ar_outfile.fd = open(ar_outfile.path, O_RDWR|O_CREAT|O_LARGEFILE, 0666);
1188ba7866cdSAli Bahrami if (ar_outfile.fd == -1) {
1189ba7866cdSAli Bahrami int err = errno;
1190ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
1191ba7866cdSAli Bahrami ar_outfile.path, strerror(err));
1192ba7866cdSAli Bahrami exit(1);
1193ba7866cdSAli Bahrami }
1194ba7866cdSAli Bahrami
1195ba7866cdSAli Bahrami /* Output magic string */
1196ba7866cdSAli Bahrami arwrite(name, ar_outfile.fd, ARMAG, SARMAG);
1197ba7866cdSAli Bahrami
1198ba7866cdSAli Bahrami /*
1199ba7866cdSAli Bahrami * The symbol table member is always first if present. Note that
1200ba7866cdSAli Bahrami * writesymtab() uses the member offsets computed by sizeofmembers()
1201ba7866cdSAli Bahrami * above.
1202ba7866cdSAli Bahrami */
1203ba7866cdSAli Bahrami if (found_obj)
1204ba7866cdSAli Bahrami writesymtab(name, ar_outfile.fd, nsyms, symlist,
1205ba7866cdSAli Bahrami symtbl_eltsize);
1206ba7866cdSAli Bahrami
12077c478bd9Sstevel@tonic-gate if (longnames) {
1208ba7866cdSAli Bahrami write_member_header(name, ar_outfile.fd, 0,
1209ba7866cdSAli Bahrami MSG_ORIG(MSG_STR_DSLASH), time(0), 0, 0, 0,
1210ba7866cdSAli Bahrami long_strtbl.used);
1211ba7866cdSAli Bahrami arwrite(name, ar_outfile.fd, long_strtbl.base,
1212ba7866cdSAli Bahrami long_strtbl.used);
12137c478bd9Sstevel@tonic-gate }
1214ba7866cdSAli Bahrami
1215ba7866cdSAli Bahrami /*
1216ba7866cdSAli Bahrami * The accuracy of the symbol table depends on our having calculated
1217ba7866cdSAli Bahrami * the size of the archive accurately to this point. If this is a
1218ba7866cdSAli Bahrami * debug build, verify it.
1219ba7866cdSAli Bahrami */
1220ba7866cdSAli Bahrami assert(arsize == lseek(ar_outfile.fd, 0, SEEK_CUR));
1221ba7866cdSAli Bahrami
1222ba7866cdSAli Bahrami #ifndef XPG4
1223ba7866cdSAli Bahrami if (cmd_info->opt_flgs & v_FLAG) {
1224ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_BER_MES_WRITE),
1225ba7866cdSAli Bahrami cmd_info->arnam);
1226ba7866cdSAli Bahrami }
1227ba7866cdSAli Bahrami #endif
1228ba7866cdSAli Bahrami
1229ba7866cdSAli Bahrami /*
1230ba7866cdSAli Bahrami * Fill pad_bytes array with newline characters. This array
1231ba7866cdSAli Bahrami * is used to supply padding bytes at the end of ELF objects.
1232ba7866cdSAli Bahrami * There can never be more tha PADSZ such bytes, so this number
1233ba7866cdSAli Bahrami * will always suffice.
1234ba7866cdSAli Bahrami */
1235ba7866cdSAli Bahrami for (pad_cnt = 0; pad_cnt < PADSZ; pad_cnt++)
1236ba7866cdSAli Bahrami pad_bytes[pad_cnt] = '\n';
1237ba7866cdSAli Bahrami
12387c478bd9Sstevel@tonic-gate for (fptr = listhead; fptr; fptr = fptr->ar_next) {
1239ba7866cdSAli Bahrami /*
1240ba7866cdSAli Bahrami * We computed the expected offset for each ELF member and
1241ba7866cdSAli Bahrami * used those offsets to fill the symbol table. If this is
1242ba7866cdSAli Bahrami * a debug build, verify that the computed offset was right.
1243ba7866cdSAli Bahrami */
1244ba7866cdSAli Bahrami is_elf = (fptr->ar_flag & (F_CLASS32 | F_CLASS64)) != 0;
1245ba7866cdSAli Bahrami assert(!is_elf ||
1246ba7866cdSAli Bahrami (fptr->ar_offset == lseek(ar_outfile.fd, 0, SEEK_CUR)));
12477c478bd9Sstevel@tonic-gate
12487c478bd9Sstevel@tonic-gate /*
12497c478bd9Sstevel@tonic-gate * NOTE:
12507c478bd9Sstevel@tonic-gate * The mem_header->ar_name[] is set to a NULL string
12517c478bd9Sstevel@tonic-gate * if the archive member header has some error.
12527c478bd9Sstevel@tonic-gate * (See elf_getarhdr() man page.)
12537c478bd9Sstevel@tonic-gate * It is set to NULL for example, the ar command reads
12547c478bd9Sstevel@tonic-gate * the archive files created by SunOS 4.1 system.
12557c478bd9Sstevel@tonic-gate * See c block comment in cmd.c, "Incompatible Archive Header".
12567c478bd9Sstevel@tonic-gate */
12577c478bd9Sstevel@tonic-gate if (fptr->ar_name[0] == 0) {
12587c478bd9Sstevel@tonic-gate fptr->ar_longname = fptr->ar_rawname;
12597c478bd9Sstevel@tonic-gate (void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME);
12607c478bd9Sstevel@tonic-gate }
1261ba7866cdSAli Bahrami write_member_header(name, ar_outfile.fd, is_elf,
1262ba7866cdSAli Bahrami (strlen(fptr->ar_longname) <= (unsigned)SNAME-2) ?
1263ba7866cdSAli Bahrami trimslash(fptr->ar_longname) : fptr->ar_name,
1264ba7866cdSAli Bahrami EC_WORD(fptr->ar_date), fptr->ar_uid, fptr->ar_gid,
1265ba7866cdSAli Bahrami fptr->ar_mode, fptr->ar_size + fptr->ar_padding);
12667c478bd9Sstevel@tonic-gate
12677c478bd9Sstevel@tonic-gate
1268ba7866cdSAli Bahrami if ((fptr->ar_flag & F_ELFRAW) == 0) {
1269ba7866cdSAli Bahrami /*
1270ba7866cdSAli Bahrami * The file doesn't come from the archive, and is
1271ba7866cdSAli Bahrami * therefore not already in memory(fptr->ar_contents)
1272ba7866cdSAli Bahrami * so open it and do a direct file-to-file transfer of
1273ba7866cdSAli Bahrami * its contents. We use the sendfile() system call
1274ba7866cdSAli Bahrami * to make the kernel do the transfer, so we don't have
1275ba7866cdSAli Bahrami * to buffer data in process, and we trust that the
1276ba7866cdSAli Bahrami * kernel will use an optimal transfer strategy.
1277ba7866cdSAli Bahrami */
1278ba7866cdSAli Bahrami if ((fd = open(fptr->ar_pathname, O_RDONLY)) == -1) {
1279ba7866cdSAli Bahrami int err = errno;
1280ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
1281ba7866cdSAli Bahrami fptr->ar_longname, strerror(err));
12827c478bd9Sstevel@tonic-gate exit(1);
12837c478bd9Sstevel@tonic-gate }
1284ba7866cdSAli Bahrami if (stat(fptr->ar_pathname, &stbuf) < 0) {
1285ba7866cdSAli Bahrami int err = errno;
1286ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
1287ba7866cdSAli Bahrami fptr->ar_longname, strerror(err));
1288ba7866cdSAli Bahrami (void) close(fd);
1289ba7866cdSAli Bahrami exit(1);
12907c478bd9Sstevel@tonic-gate }
1291ba7866cdSAli Bahrami off = 0;
1292ba7866cdSAli Bahrami if (sendfile(ar_outfile.fd, fd, &off,
1293ba7866cdSAli Bahrami stbuf.st_size) != stbuf.st_size) {
1294ba7866cdSAli Bahrami int err = errno;
1295ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE),
1296ba7866cdSAli Bahrami name, strerror(err));
1297ba7866cdSAli Bahrami exit(2);
1298ba7866cdSAli Bahrami }
1299ba7866cdSAli Bahrami (void) close(fd);
13007c478bd9Sstevel@tonic-gate } else {
1301ba7866cdSAli Bahrami /* Archive member is in memory. Write it out */
1302ba7866cdSAli Bahrami arwrite(name, ar_outfile.fd, fptr->ar_contents,
13037c478bd9Sstevel@tonic-gate fptr->ar_size);
13047c478bd9Sstevel@tonic-gate }
13057c478bd9Sstevel@tonic-gate
13067c478bd9Sstevel@tonic-gate /*
1307ba7866cdSAli Bahrami * All archive members are padded to at least a boundary of 2.
1308ba7866cdSAli Bahrami * The expression ((fptr->ar_size & 0x1) != 0) yields 1 for
1309ba7866cdSAli Bahrami * odd boundaries, and 0 for even ones. To this, we add
1310ba7866cdSAli Bahrami * whatever padding is needed for ELF objects.
13117c478bd9Sstevel@tonic-gate */
1312ba7866cdSAli Bahrami pad_cnt = ((fptr->ar_size & 0x1) != 0) + fptr->ar_padding;
1313ba7866cdSAli Bahrami if (pad_cnt > 0)
1314ba7866cdSAli Bahrami arwrite(name, ar_outfile.fd, pad_bytes, pad_cnt);
1315ba7866cdSAli Bahrami }
1316ba7866cdSAli Bahrami
1317ba7866cdSAli Bahrami /*
1318ba7866cdSAli Bahrami * All archive output is done.
1319ba7866cdSAli Bahrami */
1320ba7866cdSAli Bahrami if (close(ar_outfile.fd) < 0) {
1321ba7866cdSAli Bahrami int err = errno;
1322ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_CLOSE), ar_outfile.path,
1323ba7866cdSAli Bahrami strerror(err));
1324ba7866cdSAli Bahrami exit(1);
1325ba7866cdSAli Bahrami }
1326ba7866cdSAli Bahrami ar_outfile.fd = -1; /* Prevent removal on exit */
13277c478bd9Sstevel@tonic-gate (void) elf_end(cmd_info->arf);
13287c478bd9Sstevel@tonic-gate (void) close(cmd_info->afd);
13297c478bd9Sstevel@tonic-gate
13307c478bd9Sstevel@tonic-gate /*
1331ba7866cdSAli Bahrami * If updating an existing archive, rename the new version on
1332ba7866cdSAli Bahrami * top of the original.
13337c478bd9Sstevel@tonic-gate */
1334ba7866cdSAli Bahrami if (!new_archive) {
13357c478bd9Sstevel@tonic-gate /*
1336ba7866cdSAli Bahrami * Prevent the replacement of the original archive from
1337ba7866cdSAli Bahrami * being interrupted, to lower the possibility of an
1338ba7866cdSAli Bahrami * interrupt destroying a pre-existing archive.
13397c478bd9Sstevel@tonic-gate */
1340ba7866cdSAli Bahrami establish_sighandler(SIG_IGN);
1341ba7866cdSAli Bahrami
1342ba7866cdSAli Bahrami if (rename(ar_outfile.path, name) < 0) {
1343ba7866cdSAli Bahrami int err = errno;
1344ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_RENAME),
1345ba7866cdSAli Bahrami ar_outfile.path, name, strerror(err));
1346ba7866cdSAli Bahrami (void) unlink(ar_outfile.path);
13477c478bd9Sstevel@tonic-gate exit(1);
13487c478bd9Sstevel@tonic-gate }
1349ba7866cdSAli Bahrami (void) chmod(name, ar_stbuf.st_mode & 0777);
1350ba7866cdSAli Bahrami if (chown(name, ar_stbuf.st_uid, ar_stbuf.st_gid) >= 0)
1351ba7866cdSAli Bahrami (void) chmod(name, ar_stbuf.st_mode & 07777);
1352ba7866cdSAli Bahrami
13537c478bd9Sstevel@tonic-gate }
13547c478bd9Sstevel@tonic-gate }
13557c478bd9Sstevel@tonic-gate
1356ba7866cdSAli Bahrami /*
1357ba7866cdSAli Bahrami * Examine all the archive members, enter any member names longer than
1358ba7866cdSAli Bahrami * 15 characters into the long name string table, and count the number
1359ba7866cdSAli Bahrami * of names found.
1360ba7866cdSAli Bahrami *
1361ba7866cdSAli Bahrami * Returns the size of the resulting archive member, including the
1362ba7866cdSAli Bahrami * member header.
1363ba7866cdSAli Bahrami */
1364ba7866cdSAli Bahrami static size_t
mklong_tab(void)1365ba7866cdSAli Bahrami mklong_tab(void)
13667c478bd9Sstevel@tonic-gate {
13677c478bd9Sstevel@tonic-gate ARFILE *fptr;
1368ba7866cdSAli Bahrami size_t longnames = 0;
13697c478bd9Sstevel@tonic-gate
13707c478bd9Sstevel@tonic-gate for (fptr = listhead; fptr; fptr = fptr->ar_next) {
13717c478bd9Sstevel@tonic-gate if (strlen(fptr->ar_longname) >= (unsigned)SNAME-1) {
1372ba7866cdSAli Bahrami longnames++;
1373ba7866cdSAli Bahrami savelongname(fptr);
13747c478bd9Sstevel@tonic-gate }
13757c478bd9Sstevel@tonic-gate }
1376ba7866cdSAli Bahrami
13777c478bd9Sstevel@tonic-gate /* round up table that keeps the long filenames */
1378ba7866cdSAli Bahrami if (longnames > 0)
1379ba7866cdSAli Bahrami strtbl_pad(&long_strtbl, pad(long_strtbl.used, 4), '\n');
1380ba7866cdSAli Bahrami
1381ba7866cdSAli Bahrami return (longnames);
13827c478bd9Sstevel@tonic-gate }
13837c478bd9Sstevel@tonic-gate
1384ba7866cdSAli Bahrami /*
1385ba7866cdSAli Bahrami * Write 32/64-bit words into buffer in archive symbol table
1386ba7866cdSAli Bahrami * standard byte order (MSB).
1387ba7866cdSAli Bahrami */
1388ba7866cdSAli Bahrami static char *
sputl32(uint32_t n,char * cp)1389ba7866cdSAli Bahrami sputl32(uint32_t n, char *cp)
13907c478bd9Sstevel@tonic-gate {
13917c478bd9Sstevel@tonic-gate *cp++ = n >> 24;
13927c478bd9Sstevel@tonic-gate *cp++ = n >> 16;
13937c478bd9Sstevel@tonic-gate *cp++ = n >> 8;
13947c478bd9Sstevel@tonic-gate
13957c478bd9Sstevel@tonic-gate *cp++ = n & 255;
1396ba7866cdSAli Bahrami
1397ba7866cdSAli Bahrami return (cp);
1398ba7866cdSAli Bahrami }
1399ba7866cdSAli Bahrami
1400ba7866cdSAli Bahrami static char *
sputl64(uint64_t n,char * cp)1401ba7866cdSAli Bahrami sputl64(uint64_t n, char *cp)
1402ba7866cdSAli Bahrami {
1403ba7866cdSAli Bahrami *cp++ = n >> 56;
1404ba7866cdSAli Bahrami *cp++ = n >> 48;
1405ba7866cdSAli Bahrami *cp++ = n >> 40;
1406ba7866cdSAli Bahrami *cp++ = n >> 32;
1407ba7866cdSAli Bahrami
1408ba7866cdSAli Bahrami *cp++ = n >> 24;
1409ba7866cdSAli Bahrami *cp++ = n >> 16;
1410ba7866cdSAli Bahrami *cp++ = n >> 8;
1411ba7866cdSAli Bahrami
1412ba7866cdSAli Bahrami *cp++ = n & 255;
1413ba7866cdSAli Bahrami
1414ba7866cdSAli Bahrami return (cp);
14157c478bd9Sstevel@tonic-gate }
14167c478bd9Sstevel@tonic-gate
14177c478bd9Sstevel@tonic-gate static int
search_sym_tab(const char * arname,ARFILE * fptr,Elf * elf,Elf_Scn * scn,size_t * nsyms,ARFILEP ** symlist,size_t * num_errs)1418ba7866cdSAli Bahrami search_sym_tab(const char *arname, ARFILE *fptr, Elf *elf, Elf_Scn *scn,
1419ba7866cdSAli Bahrami size_t *nsyms, ARFILEP **symlist, size_t *num_errs)
14207c478bd9Sstevel@tonic-gate {
14217c478bd9Sstevel@tonic-gate Elf_Data *str_data, *sym_data; /* string table, symbol table */
14227c478bd9Sstevel@tonic-gate Elf_Scn *str_scn;
14237c478bd9Sstevel@tonic-gate GElf_Sxword no_of_symbols;
14247c478bd9Sstevel@tonic-gate GElf_Shdr shdr;
14257c478bd9Sstevel@tonic-gate int counter;
14267c478bd9Sstevel@tonic-gate int str_shtype;
14277c478bd9Sstevel@tonic-gate char *symname;
14287c478bd9Sstevel@tonic-gate static ARFILEP *sym_ptr = 0;
14297c478bd9Sstevel@tonic-gate static ARFILEP *nextsym = NULL;
14307c478bd9Sstevel@tonic-gate static int syms_left = 0;
14317c478bd9Sstevel@tonic-gate char *fname = fptr->ar_pathname;
14327c478bd9Sstevel@tonic-gate
14337c478bd9Sstevel@tonic-gate (void) gelf_getshdr(scn, &shdr);
14347c478bd9Sstevel@tonic-gate str_scn = elf_getscn(elf, shdr.sh_link); /* index for string table */
14357c478bd9Sstevel@tonic-gate if (str_scn == NULL) {
14367c478bd9Sstevel@tonic-gate if (fname != NULL)
1437ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA_FILE),
1438ba7866cdSAli Bahrami fname, elf_errmsg(-1));
14397c478bd9Sstevel@tonic-gate else
1440ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA_AR),
1441ba7866cdSAli Bahrami arname, fptr->ar_longname, elf_errmsg(-1));
14427c478bd9Sstevel@tonic-gate (*num_errs)++;
14437c478bd9Sstevel@tonic-gate return (-1);
14447c478bd9Sstevel@tonic-gate }
14457c478bd9Sstevel@tonic-gate
14467c478bd9Sstevel@tonic-gate no_of_symbols = shdr.sh_size / shdr.sh_entsize;
14477c478bd9Sstevel@tonic-gate if (no_of_symbols == -1) {
1448ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_01));
14497c478bd9Sstevel@tonic-gate return (-1);
14507c478bd9Sstevel@tonic-gate }
14517c478bd9Sstevel@tonic-gate
14527c478bd9Sstevel@tonic-gate (void) gelf_getshdr(str_scn, &shdr);
14537c478bd9Sstevel@tonic-gate str_shtype = shdr.sh_type;
14547c478bd9Sstevel@tonic-gate if (str_shtype == -1) {
14557c478bd9Sstevel@tonic-gate if (fname != NULL)
1456ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA_FILE),
1457ba7866cdSAli Bahrami fname, elf_errmsg(-1));
14587c478bd9Sstevel@tonic-gate else
1459ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA_AR),
1460ba7866cdSAli Bahrami arname, fptr->ar_longname, elf_errmsg(-1));
14617c478bd9Sstevel@tonic-gate (*num_errs)++;
14627c478bd9Sstevel@tonic-gate return (-1);
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate /* This test must happen before testing the string table. */
14667c478bd9Sstevel@tonic-gate if (no_of_symbols == 1)
14677c478bd9Sstevel@tonic-gate return (0); /* no symbols; 0th symbol is the non-symbol */
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate if (str_shtype != SHT_STRTAB) {
14707c478bd9Sstevel@tonic-gate if (fname != NULL)
1471ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_NOSTR_FILE),
14727c478bd9Sstevel@tonic-gate fname);
14737c478bd9Sstevel@tonic-gate else
1474ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_NOSTR_AR),
1475ba7866cdSAli Bahrami arname, fptr->ar_longname);
14767c478bd9Sstevel@tonic-gate return (0);
14777c478bd9Sstevel@tonic-gate }
14787c478bd9Sstevel@tonic-gate str_data = 0;
14797c478bd9Sstevel@tonic-gate if ((str_data = elf_getdata(str_scn, str_data)) == 0) {
14807c478bd9Sstevel@tonic-gate if (fname != NULL)
1481ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_NODAT_FILE),
14827c478bd9Sstevel@tonic-gate fname);
14837c478bd9Sstevel@tonic-gate else
1484ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_NODAT_AR),
1485ba7866cdSAli Bahrami arname, fptr->ar_longname);
14867c478bd9Sstevel@tonic-gate return (0);
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate if (str_data->d_size == 0) {
14897c478bd9Sstevel@tonic-gate if (fname != NULL)
1490ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_ZDAT_FILE),
14917c478bd9Sstevel@tonic-gate fname);
14927c478bd9Sstevel@tonic-gate else
1493ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_ZDAT_AR),
1494ba7866cdSAli Bahrami arname, fptr->ar_longname);
14957c478bd9Sstevel@tonic-gate return (0);
14967c478bd9Sstevel@tonic-gate }
14977c478bd9Sstevel@tonic-gate sym_data = 0;
14987c478bd9Sstevel@tonic-gate if ((sym_data = elf_getdata(scn, sym_data)) == NULL) {
14997c478bd9Sstevel@tonic-gate if (fname != NULL)
1500ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_ELF_LIB_FILE),
15017c478bd9Sstevel@tonic-gate fname, elf_errmsg(-1));
15027c478bd9Sstevel@tonic-gate else
1503ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_ELF_LIB_AR),
1504ba7866cdSAli Bahrami arname, fptr->ar_longname, elf_errmsg(-1));
15057c478bd9Sstevel@tonic-gate return (0);
15067c478bd9Sstevel@tonic-gate }
15077c478bd9Sstevel@tonic-gate
15087c478bd9Sstevel@tonic-gate /* start at 1, first symbol entry is ignored */
15097c478bd9Sstevel@tonic-gate for (counter = 1; counter < no_of_symbols; counter++) {
15107c478bd9Sstevel@tonic-gate GElf_Sym sym;
15117c478bd9Sstevel@tonic-gate (void) gelf_getsym(sym_data, counter, &sym);
15127c478bd9Sstevel@tonic-gate
15137c478bd9Sstevel@tonic-gate symname = (char *)(str_data->d_buf) + sym.st_name;
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate if (((GELF_ST_BIND(sym.st_info) == STB_GLOBAL) ||
15167c478bd9Sstevel@tonic-gate (GELF_ST_BIND(sym.st_info) == STB_WEAK)) &&
15177c478bd9Sstevel@tonic-gate (sym.st_shndx != SHN_UNDEF)) {
15187c478bd9Sstevel@tonic-gate if (!syms_left) {
15197c478bd9Sstevel@tonic-gate sym_ptr = malloc((SYMCHUNK+1)
15207c478bd9Sstevel@tonic-gate * sizeof (ARFILEP));
15217c478bd9Sstevel@tonic-gate if (sym_ptr == NULL) {
1522ba7866cdSAli Bahrami int err = errno;
1523ba7866cdSAli Bahrami (void) fprintf(stderr,
1524ba7866cdSAli Bahrami MSG_INTL(MSG_MALLOC),
1525ba7866cdSAli Bahrami strerror(err));
15267c478bd9Sstevel@tonic-gate exit(1);
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate syms_left = SYMCHUNK;
15297c478bd9Sstevel@tonic-gate if (nextsym)
15307c478bd9Sstevel@tonic-gate *nextsym = (ARFILEP)sym_ptr;
15317c478bd9Sstevel@tonic-gate else
15327c478bd9Sstevel@tonic-gate *symlist = sym_ptr;
15337c478bd9Sstevel@tonic-gate nextsym = sym_ptr;
15347c478bd9Sstevel@tonic-gate }
15357c478bd9Sstevel@tonic-gate sym_ptr = nextsym;
15367c478bd9Sstevel@tonic-gate nextsym++;
15377c478bd9Sstevel@tonic-gate syms_left--;
15387c478bd9Sstevel@tonic-gate (*nsyms)++;
15397c478bd9Sstevel@tonic-gate *sym_ptr = fptr;
15407c478bd9Sstevel@tonic-gate savename(symname); /* put name in the archiver's */
15417c478bd9Sstevel@tonic-gate /* symbol table string table */
15427c478bd9Sstevel@tonic-gate }
15437c478bd9Sstevel@tonic-gate }
15447c478bd9Sstevel@tonic-gate return (0);
15457c478bd9Sstevel@tonic-gate }
15467c478bd9Sstevel@tonic-gate
15477c478bd9Sstevel@tonic-gate /*
15487c478bd9Sstevel@tonic-gate * Get the output file size
15497c478bd9Sstevel@tonic-gate */
1550ba7866cdSAli Bahrami static size_t
sizeofmembers(size_t psum)1551ba7866cdSAli Bahrami sizeofmembers(size_t psum)
15527c478bd9Sstevel@tonic-gate {
1553ba7866cdSAli Bahrami size_t sum = 0;
15547c478bd9Sstevel@tonic-gate ARFILE *fptr;
1555ba7866cdSAli Bahrami size_t hdrsize = sizeof (struct ar_hdr);
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate for (fptr = listhead; fptr; fptr = fptr->ar_next) {
15587c478bd9Sstevel@tonic-gate fptr->ar_offset = psum + sum;
15597c478bd9Sstevel@tonic-gate sum += fptr->ar_size;
15607c478bd9Sstevel@tonic-gate if (fptr->ar_size & 01)
15617c478bd9Sstevel@tonic-gate sum++;
15627c478bd9Sstevel@tonic-gate sum += hdrsize;
15637c478bd9Sstevel@tonic-gate
156460fc76daSab196087 /*
156560fc76daSab196087 * If the current item, and the next item are both ELF
156660fc76daSab196087 * objects, then add padding to current item so that the
1567ba7866cdSAli Bahrami * data in the next item will have PADSZ alignment.
156860fc76daSab196087 *
156960fc76daSab196087 * In any other case, set the padding to 0. If the
157060fc76daSab196087 * item comes from another archive, it may be carrying
157160fc76daSab196087 * a non-zero padding value from that archive that does
157260fc76daSab196087 * not apply to the one we are about to build.
157360fc76daSab196087 */
15747c478bd9Sstevel@tonic-gate if ((fptr->ar_flag & (F_CLASS32 | F_CLASS64)) &&
15759d6538abSab196087 fptr->ar_next &&
15769d6538abSab196087 (fptr->ar_next->ar_flag & (F_CLASS32 | F_CLASS64))) {
1577ba7866cdSAli Bahrami fptr->ar_padding = pad(psum + sum + hdrsize, PADSZ);
15789d6538abSab196087 sum += fptr->ar_padding;
157960fc76daSab196087 } else {
158060fc76daSab196087 fptr->ar_padding = 0;
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate }
15837c478bd9Sstevel@tonic-gate return (sum);
15847c478bd9Sstevel@tonic-gate }
15857c478bd9Sstevel@tonic-gate
15867c478bd9Sstevel@tonic-gate /*
1587ba7866cdSAli Bahrami * Compute the size of the symbol table archive member.
1588ba7866cdSAli Bahrami *
1589ba7866cdSAli Bahrami * entry:
1590ba7866cdSAli Bahrami * nsyms - # of symbols in the table
1591ba7866cdSAli Bahrami * found_obj - TRUE if the archive contains any ELF objects
1592ba7866cdSAli Bahrami * eltsize - Size of the integer type to use for the symbol
1593ba7866cdSAli Bahrami * table. 4 for 32-bit tables, and 8 for 64-bit tables.
15947c478bd9Sstevel@tonic-gate */
1595ba7866cdSAli Bahrami static size_t
sizeof_symtbl(size_t nsyms,int found_obj,size_t eltsize)1596ba7866cdSAli Bahrami sizeof_symtbl(size_t nsyms, int found_obj, size_t eltsize)
15979d6538abSab196087 {
1598ba7866cdSAli Bahrami size_t sum = 0;
15999d6538abSab196087
1600ba7866cdSAli Bahrami if (found_obj) {
1601ba7866cdSAli Bahrami /* Member header, symbol count, and one slot per symbol */
1602ba7866cdSAli Bahrami sum += sizeof (struct ar_hdr) + ((nsyms + 1) * eltsize);
1603ba7866cdSAli Bahrami sum += sym_strtbl.used;
1604ba7866cdSAli Bahrami }
1605ba7866cdSAli Bahrami
16067c478bd9Sstevel@tonic-gate return (sum);
16077c478bd9Sstevel@tonic-gate }
16087c478bd9Sstevel@tonic-gate
16097c478bd9Sstevel@tonic-gate static void
arwrite(const char * name,int nfd,const char * dst,size_t size)1610ba7866cdSAli Bahrami arwrite(const char *name, int nfd, const char *dst, size_t size) {
16117c478bd9Sstevel@tonic-gate if (write(nfd, dst, size) != size) {
1612ba7866cdSAli Bahrami int err = errno;
1613ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE),
1614ba7866cdSAli Bahrami name, strerror(err));
16157c478bd9Sstevel@tonic-gate exit(2);
16167c478bd9Sstevel@tonic-gate }
16177c478bd9Sstevel@tonic-gate }
16187c478bd9Sstevel@tonic-gate
1619ba7866cdSAli Bahrami static const char *
make_tmpname(const char * filename)1620ba7866cdSAli Bahrami make_tmpname(const char *filename) {
1621ba7866cdSAli Bahrami char *slash, *tmpname;
1622ba7866cdSAli Bahrami size_t prefix_cnt = 0;
16237c478bd9Sstevel@tonic-gate
16247c478bd9Sstevel@tonic-gate /*
1625ba7866cdSAli Bahrami * If there is a path prefix in front of the filename, we
1626ba7866cdSAli Bahrami * want to put the temporary file in the same directory.
1627ba7866cdSAli Bahrami * Determine the length of the path.
16287c478bd9Sstevel@tonic-gate */
1629ba7866cdSAli Bahrami slash = strrchr(filename, '/');
1630ba7866cdSAli Bahrami if (slash != NULL)
1631ba7866cdSAli Bahrami prefix_cnt = slash - filename + 1;
1632ba7866cdSAli Bahrami tmpname = malloc(prefix_cnt + MSG_STR_MKTEMP_SIZE + 1);
1633ba7866cdSAli Bahrami if (tmpname == NULL) {
1634ba7866cdSAli Bahrami int err = errno;
1635ba7866cdSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
1636ba7866cdSAli Bahrami exit(1);
16377c478bd9Sstevel@tonic-gate }
16387c478bd9Sstevel@tonic-gate
1639ba7866cdSAli Bahrami if (prefix_cnt > 0)
1640ba7866cdSAli Bahrami (void) strncpy(tmpname, filename, prefix_cnt);
1641ba7866cdSAli Bahrami (void) strcpy(tmpname + prefix_cnt, MSG_ORIG(MSG_STR_MKTEMP));
1642ba7866cdSAli Bahrami (void) mktemp(tmpname);
1643ba7866cdSAli Bahrami
1644ba7866cdSAli Bahrami return (tmpname);
16457c478bd9Sstevel@tonic-gate }
1646