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 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 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 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 * 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