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 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * 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 */ 215aefb655Srie 227c478bd9Sstevel@tonic-gate /* 235aefb655Srie * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate * 267c478bd9Sstevel@tonic-gate * dldump(3c) creates a new file image from the specified input file. 277c478bd9Sstevel@tonic-gate */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/param.h> 307c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 317c478bd9Sstevel@tonic-gate #include <fcntl.h> 327c478bd9Sstevel@tonic-gate #include <stdio.h> 337c478bd9Sstevel@tonic-gate #include <libelf.h> 347c478bd9Sstevel@tonic-gate #include <link.h> 357c478bd9Sstevel@tonic-gate #include <dlfcn.h> 367c478bd9Sstevel@tonic-gate #include <stdlib.h> 377c478bd9Sstevel@tonic-gate #include <string.h> 387c478bd9Sstevel@tonic-gate #include <unistd.h> 397c478bd9Sstevel@tonic-gate #include <errno.h> 407c478bd9Sstevel@tonic-gate #include "libld.h" 417c478bd9Sstevel@tonic-gate #include "msg.h" 427c478bd9Sstevel@tonic-gate #include "_librtld.h" 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * Generic clean up routine 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate static void 487c478bd9Sstevel@tonic-gate cleanup(Elf *ielf, Elf *oelf, Elf *melf, Cache *icache, Cache *mcache, 497c478bd9Sstevel@tonic-gate int fd, const char *opath) 507c478bd9Sstevel@tonic-gate { 517c478bd9Sstevel@tonic-gate if (icache) { 527c478bd9Sstevel@tonic-gate Cache * _icache = icache; 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate for (++_icache; _icache->c_flags != FLG_C_END; _icache++) { 557c478bd9Sstevel@tonic-gate if (_icache->c_info) 567c478bd9Sstevel@tonic-gate (void) free(_icache->c_info); 577c478bd9Sstevel@tonic-gate } 587c478bd9Sstevel@tonic-gate (void) free((void *)icache); 597c478bd9Sstevel@tonic-gate } 607c478bd9Sstevel@tonic-gate if (mcache) 617c478bd9Sstevel@tonic-gate (void) free((void *)mcache); 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate if (ielf) 647c478bd9Sstevel@tonic-gate (void) elf_end(ielf); 657c478bd9Sstevel@tonic-gate if (oelf) 667c478bd9Sstevel@tonic-gate (void) elf_end(oelf); 677c478bd9Sstevel@tonic-gate if (melf) 687c478bd9Sstevel@tonic-gate (void) elf_end(melf); 697c478bd9Sstevel@tonic-gate if (fd) 707c478bd9Sstevel@tonic-gate (void) close(fd); 717c478bd9Sstevel@tonic-gate if (opath) 727c478bd9Sstevel@tonic-gate (void) unlink(opath); 737c478bd9Sstevel@tonic-gate } 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* 767c478bd9Sstevel@tonic-gate * The dldump(3x) interface directs control to the runtime linker. The runtime 777c478bd9Sstevel@tonic-gate * linker brings in librtld.so.1 to provide the underlying support for this 787c478bd9Sstevel@tonic-gate * call (this is because librtld.so.1 requires libelf.so.1, and the whole wad 797c478bd9Sstevel@tonic-gate * is rather expensive to drag around with ld.so.1). 807c478bd9Sstevel@tonic-gate * 817c478bd9Sstevel@tonic-gate * rt_dldump(Rt_map * lmp, const char * opath, int flags, Addr addr) 827c478bd9Sstevel@tonic-gate * 837c478bd9Sstevel@tonic-gate * lmp provides the link-map of the ipath (the input file). 847c478bd9Sstevel@tonic-gate * 857c478bd9Sstevel@tonic-gate * opath specifies the output file. 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate * flags provides a variety of options that control how the new image will be 887c478bd9Sstevel@tonic-gate * relocated (if required). 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * addr indicates the base address at which the associated input image is mapped 917c478bd9Sstevel@tonic-gate * within the process. 927c478bd9Sstevel@tonic-gate * 937c478bd9Sstevel@tonic-gate * The modes of operation and the various flags provide a number of combinations 947c478bd9Sstevel@tonic-gate * of images that can be created, some are useful, some maybe not. The 957c478bd9Sstevel@tonic-gate * following provide a couple of basic models for dldump(3x) use: 967c478bd9Sstevel@tonic-gate * 977c478bd9Sstevel@tonic-gate * new executable - dldump(0, outfile, RTLD_MEMORY) 987c478bd9Sstevel@tonic-gate * 997c478bd9Sstevel@tonic-gate * A dynamic executable may undergo some initialization 1007c478bd9Sstevel@tonic-gate * and the results of this saved in a new file for later 1017c478bd9Sstevel@tonic-gate * execution. The executable will presumable update 1027c478bd9Sstevel@tonic-gate * parts of its data segment and heap (note that the heap 1037c478bd9Sstevel@tonic-gate * should be acquired using malloc() so that it follows 1047c478bd9Sstevel@tonic-gate * the end of the data segment for this technique to be 1057c478bd9Sstevel@tonic-gate * useful). These updated memory elements are saved to the 1067c478bd9Sstevel@tonic-gate * new file, including a new .SUNW_heap section if 1077c478bd9Sstevel@tonic-gate * required. 1087c478bd9Sstevel@tonic-gate * 1097c478bd9Sstevel@tonic-gate * For greatest flexibility, no relocated information 1107c478bd9Sstevel@tonic-gate * should be saved (by default any relocated information is 1117c478bd9Sstevel@tonic-gate * returned to the value it had in its original file). 1127c478bd9Sstevel@tonic-gate * This allows the new image to bind to new dynamic objects 1137c478bd9Sstevel@tonic-gate * when executed on the same or newer upgrades of the OS. 1147c478bd9Sstevel@tonic-gate * 1157c478bd9Sstevel@tonic-gate * Fixing relocations by applying RTLD_REL_ALL will bind 1167c478bd9Sstevel@tonic-gate * the image to the dependencies presently mapped as part 1177c478bd9Sstevel@tonic-gate * of the process. Thus the new executable will only work 1187c478bd9Sstevel@tonic-gate * correctly when these same dependencies map to exactly 1197c478bd9Sstevel@tonic-gate * to the same locations. (note that RTLD_REL_RELATIVE will 1207c478bd9Sstevel@tonic-gate * have no effect as dynamic executables commonly don't 1217c478bd9Sstevel@tonic-gate * contain any relative relocations). 1227c478bd9Sstevel@tonic-gate * 1237c478bd9Sstevel@tonic-gate * new shared object - dldump(infile, outfile, RTLD_REL_RELATIVE) 1247c478bd9Sstevel@tonic-gate * 1257c478bd9Sstevel@tonic-gate * A shared object can be fixed to a known address so as 1267c478bd9Sstevel@tonic-gate * to reduce its relocation overhead on startup. Because 1277c478bd9Sstevel@tonic-gate * the new file is fixed to a new base address (which is 1287c478bd9Sstevel@tonic-gate * the address at which the object was found mapped to the 1297c478bd9Sstevel@tonic-gate * process) it is now a dynamic executable. 1307c478bd9Sstevel@tonic-gate * 1317c478bd9Sstevel@tonic-gate * Data changes that have occurred due to the object 1327c478bd9Sstevel@tonic-gate * gaining control (at the least this would be .init 1337c478bd9Sstevel@tonic-gate * processing) will not be carried over to the new image. 1347c478bd9Sstevel@tonic-gate * 1357c478bd9Sstevel@tonic-gate * By only performing relative relocations all global 1367c478bd9Sstevel@tonic-gate * relocations are available for unique binding to each 1377c478bd9Sstevel@tonic-gate * process - thus interposition etc. is still available. 1387c478bd9Sstevel@tonic-gate * 1397c478bd9Sstevel@tonic-gate * Using RTLD_REL_ALL will fix all relocations in the new 1407c478bd9Sstevel@tonic-gate * file, which will certainly provide for faster startup 1417c478bd9Sstevel@tonic-gate * of the new image, but at the loss of interposition 1427c478bd9Sstevel@tonic-gate * flexibility. 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate int 1457c478bd9Sstevel@tonic-gate rt_dldump(Rt_map *lmp, const char *opath, int flags, Addr addr) 1467c478bd9Sstevel@tonic-gate { 1477c478bd9Sstevel@tonic-gate Elf * ielf = 0, *oelf = 0, *melf = 0; 1487c478bd9Sstevel@tonic-gate Ehdr *iehdr, *oehdr, *mehdr; 1497c478bd9Sstevel@tonic-gate Phdr *iphdr, *ophdr, *data_phdr = 0; 1507c478bd9Sstevel@tonic-gate Cache *icache = 0, *_icache, *mcache = 0, *_mcache; 1517c478bd9Sstevel@tonic-gate Cache *data_cache = 0, *dyn_cache = 0; 1527c478bd9Sstevel@tonic-gate Xword rel_null_no = 0, rel_data_no = 0, rel_func_no = 0; 1537c478bd9Sstevel@tonic-gate Xword rel_entsize; 1547c478bd9Sstevel@tonic-gate Rel *rel_base = 0, *rel_null, *rel_data, *rel_func; 1557c478bd9Sstevel@tonic-gate Elf_Scn *scn; 1567c478bd9Sstevel@tonic-gate Shdr *shdr; 1577c478bd9Sstevel@tonic-gate Elf_Data *data; 1587c478bd9Sstevel@tonic-gate Half endx = 1; 1597c478bd9Sstevel@tonic-gate int fd = 0, err, num; 160*e4096c82SRichard Lowe size_t shstr_size = 1, shndx; 1617c478bd9Sstevel@tonic-gate Addr edata; 1627c478bd9Sstevel@tonic-gate char *shstr, *_shstr, *ipath = NAME(lmp); 1637c478bd9Sstevel@tonic-gate prstatus_t *status = 0, _status; 1645aefb655Srie Lm_list *lml = LIST(lmp); 1652926dd2eSrie Alist *nodirect = 0; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate if (lmp == lml_main.lm_head) { 1687c478bd9Sstevel@tonic-gate char proc[16]; 1697c478bd9Sstevel@tonic-gate int pfd; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * Get a /proc descriptor. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate (void) snprintf(proc, 16, MSG_ORIG(MSG_FMT_PROC), 1757c478bd9Sstevel@tonic-gate (int)getpid()); 1767c478bd9Sstevel@tonic-gate if ((pfd = open(proc, O_RDONLY)) == -1) { 1777c478bd9Sstevel@tonic-gate err = errno; 1785aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), proc, 1797c478bd9Sstevel@tonic-gate strerror(err)); 1807c478bd9Sstevel@tonic-gate return (1); 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate /* 1847c478bd9Sstevel@tonic-gate * If we've been asked to process the dynamic executable we 1857c478bd9Sstevel@tonic-gate * might not know its full path (this is prior to realpath() 1867c478bd9Sstevel@tonic-gate * processing becoming default), and thus use /proc to obtain a 1877c478bd9Sstevel@tonic-gate * file descriptor of the input file. 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate if ((fd = ioctl(pfd, PIOCOPENM, (void *)0)) == -1) { 1907c478bd9Sstevel@tonic-gate err = errno; 1915aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), ipath, 1927c478bd9Sstevel@tonic-gate strerror(err)); 1937c478bd9Sstevel@tonic-gate (void) close(pfd); 1947c478bd9Sstevel@tonic-gate return (1); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * Obtain the process's status structure from which we can 1997c478bd9Sstevel@tonic-gate * determine the size of the process's heap. Note, if the 2007c478bd9Sstevel@tonic-gate * application is using mapmalloc then the heap size is going 2017c478bd9Sstevel@tonic-gate * to be zero, and if we're dumping a data section that makes 2027c478bd9Sstevel@tonic-gate * reference to the malloc'ed area we're not going to get a 2037c478bd9Sstevel@tonic-gate * useful image. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate if (!(flags & RTLD_NOHEAP)) { 2067c478bd9Sstevel@tonic-gate if (ioctl(pfd, PIOCSTATUS, (void *)&_status) == -1) { 2077c478bd9Sstevel@tonic-gate err = errno; 2085aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), 2097c478bd9Sstevel@tonic-gate ipath, strerror(err)); 2107c478bd9Sstevel@tonic-gate (void) close(fd); 2117c478bd9Sstevel@tonic-gate (void) close(pfd); 2127c478bd9Sstevel@tonic-gate return (1); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate if ((flags & RTLD_MEMORY) && _status.pr_brksize) 2157c478bd9Sstevel@tonic-gate status = &_status; 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate (void) close(pfd); 2187c478bd9Sstevel@tonic-gate } else { 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * Open the specified file. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate if ((fd = open(ipath, O_RDONLY, 0)) == -1) { 2237c478bd9Sstevel@tonic-gate err = errno; 2245aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), ipath, 2257c478bd9Sstevel@tonic-gate strerror(err)); 2267c478bd9Sstevel@tonic-gate return (1); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * Initialize with the ELF library and make sure this is a suitable 2327c478bd9Sstevel@tonic-gate * ELF file we're dealing with. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate (void) elf_version(EV_CURRENT); 2357c478bd9Sstevel@tonic-gate if ((ielf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 2365aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_BEGIN), ipath); 2377c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, 0); 2387c478bd9Sstevel@tonic-gate return (1); 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate (void) close(fd); 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate if ((elf_kind(ielf) != ELF_K_ELF) || 2437c478bd9Sstevel@tonic-gate ((iehdr = elf_getehdr(ielf)) == NULL) || 2447c478bd9Sstevel@tonic-gate ((iehdr->e_type != ET_EXEC) && (iehdr->e_type != ET_DYN))) { 2455aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_IMG_ELF), ipath); 2467c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, 0, 0); 2477c478bd9Sstevel@tonic-gate return (1); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate /* 2517c478bd9Sstevel@tonic-gate * Make sure we can create the new output file. 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate if ((fd = open(opath, (O_RDWR | O_CREAT | O_TRUNC), 0777)) == -1) { 2547c478bd9Sstevel@tonic-gate err = errno; 2555aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), opath, 2567c478bd9Sstevel@tonic-gate strerror(err)); 2577c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, 0, 0); 2587c478bd9Sstevel@tonic-gate return (1); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate if ((oelf = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) { 2615aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_BEGIN), opath); 2627c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 2637c478bd9Sstevel@tonic-gate return (1); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * Obtain the input program headers. Remember the last data segments 2687c478bd9Sstevel@tonic-gate * program header entry as this will be updated later to reflect any new 2697c478bd9Sstevel@tonic-gate * heap section size. 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate if ((iphdr = elf_getphdr(ielf)) == NULL) { 2725aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETPHDR), ipath); 2737c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 2747c478bd9Sstevel@tonic-gate return (1); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate for (num = 0, ophdr = iphdr; num != iehdr->e_phnum; num++, ophdr++) { 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * Save the program header that contains the NOBITS section, or 2807c478bd9Sstevel@tonic-gate * the last loadable program header if no NOBITS exists. A 2817c478bd9Sstevel@tonic-gate * NOBITS section translates to a memory size requirement that 2827c478bd9Sstevel@tonic-gate * is greater than the file data it is mapped from. Note that 2837c478bd9Sstevel@tonic-gate * we inspect all headers just incase there only exist text 2847c478bd9Sstevel@tonic-gate * segments. 2857c478bd9Sstevel@tonic-gate */ 2867c478bd9Sstevel@tonic-gate if (ophdr->p_type == PT_LOAD) { 2877c478bd9Sstevel@tonic-gate if (ophdr->p_filesz != ophdr->p_memsz) 2887c478bd9Sstevel@tonic-gate data_phdr = ophdr; 2897c478bd9Sstevel@tonic-gate else if (data_phdr) { 2907c478bd9Sstevel@tonic-gate if (data_phdr->p_vaddr < ophdr->p_vaddr) 2917c478bd9Sstevel@tonic-gate data_phdr = ophdr; 2927c478bd9Sstevel@tonic-gate } else 2937c478bd9Sstevel@tonic-gate data_phdr = ophdr; 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * If there is no data segment, and a heap section is required, 2997c478bd9Sstevel@tonic-gate * warn the user and disable the heap addition (Note that you can't 3007c478bd9Sstevel@tonic-gate * simply append the heap to the last segment, as it might be a text 3017c478bd9Sstevel@tonic-gate * segment, and would therefore have the wrong permissions). 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate if (status && !data_phdr) { 3045aefb655Srie eprintf(lml, ERR_WARNING, MSG_INTL(MSG_IMG_DATASEG), ipath); 3057c478bd9Sstevel@tonic-gate status = 0; 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * Obtain the input files section header string table. 3107c478bd9Sstevel@tonic-gate */ 311*e4096c82SRichard Lowe 312*e4096c82SRichard Lowe if (elf_getshdrstrndx(ielf, &shndx) == -1) { 313*e4096c82SRichard Lowe eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSHDRSTRNDX), ipath); 314*e4096c82SRichard Lowe cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 315*e4096c82SRichard Lowe return (1); 316*e4096c82SRichard Lowe } 317*e4096c82SRichard Lowe if ((scn = elf_getscn(ielf, shndx)) == NULL) { 3185aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSCN), ipath); 3197c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 3207c478bd9Sstevel@tonic-gate return (1); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate if ((data = elf_getdata(scn, NULL)) == NULL) { 3235aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETDATA), ipath); 3247c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 3257c478bd9Sstevel@tonic-gate return (1); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate shstr = (char *)data->d_buf; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * Construct a cache to maintain the input files section information. 3317c478bd9Sstevel@tonic-gate * Obtain an extra cache element if a heap addition is required. Also 3327c478bd9Sstevel@tonic-gate * add an additional entry (marked FLG_C_END) to make the processing of 3337c478bd9Sstevel@tonic-gate * this cache easier. 3347c478bd9Sstevel@tonic-gate */ 335*e4096c82SRichard Lowe 336*e4096c82SRichard Lowe if (elf_getshdrnum(ielf, &shndx) == -1) { 337*e4096c82SRichard Lowe eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSHDRNUM), opath); 338*e4096c82SRichard Lowe cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 339*e4096c82SRichard Lowe return (1); 340*e4096c82SRichard Lowe } 341*e4096c82SRichard Lowe 342*e4096c82SRichard Lowe num = shndx; 343*e4096c82SRichard Lowe 3447c478bd9Sstevel@tonic-gate if (status) 3457c478bd9Sstevel@tonic-gate num++; 346*e4096c82SRichard Lowe if ((icache = calloc(num + 1, sizeof (Cache))) == 0) { 3477c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 3487c478bd9Sstevel@tonic-gate return (1); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate icache[num].c_flags = FLG_C_END; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate _icache = icache; 3537c478bd9Sstevel@tonic-gate _icache++; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* 3567c478bd9Sstevel@tonic-gate * Traverse each section from the input file collecting the appropriate 3577c478bd9Sstevel@tonic-gate * ELF information. Indicate how the section will be processed to 3587c478bd9Sstevel@tonic-gate * generate the output image. 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate for (scn = 0; scn = elf_nextscn(ielf, scn); _icache++) { 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate if ((_icache->c_shdr = shdr = elf_getshdr(scn)) == NULL) { 3635aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSHDR), ipath); 3647c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 3657c478bd9Sstevel@tonic-gate return (1); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate if ((_icache->c_data = elf_getdata(scn, NULL)) == NULL) { 3695aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETDATA), ipath); 3707c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 3717c478bd9Sstevel@tonic-gate return (1); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate _icache->c_name = shstr + (size_t)(shdr->sh_name); 3747c478bd9Sstevel@tonic-gate _icache->c_scn = scn; 3757c478bd9Sstevel@tonic-gate _icache->c_flags = 0; 3767c478bd9Sstevel@tonic-gate _icache->c_info = 0; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* 3792926dd2eSrie * Process any .SUNW_syminfo section. Symbols that are tagged 3802926dd2eSrie * as NO_DIRECT are collected, as they should not be bound to. 3812926dd2eSrie */ 3822926dd2eSrie if ((flags & ~RTLD_REL_RELATIVE) && 3832926dd2eSrie (shdr->sh_type == SHT_SUNW_syminfo)) { 3842926dd2eSrie if (syminfo(_icache, &nodirect)) { 3852926dd2eSrie cleanup(ielf, oelf, melf, icache, mcache, 3862926dd2eSrie fd, opath); 3872926dd2eSrie return (1); 3882926dd2eSrie } 3892926dd2eSrie } 3902926dd2eSrie 3912926dd2eSrie /* 3927c478bd9Sstevel@tonic-gate * If the section has no address it is not part of the mapped 3937c478bd9Sstevel@tonic-gate * image, and is unlikely to require any further processing. 3947c478bd9Sstevel@tonic-gate * The section header string table will be rewritten (this isn't 3957c478bd9Sstevel@tonic-gate * always necessary, it's only really required when relocation 3967c478bd9Sstevel@tonic-gate * sections are renamed or sections are stripped, but we do 3977c478bd9Sstevel@tonic-gate * things the same way regardless). 3987c478bd9Sstevel@tonic-gate */ 3997c478bd9Sstevel@tonic-gate if (shdr->sh_addr == 0) { 4007c478bd9Sstevel@tonic-gate if ((shdr->sh_type == SHT_STRTAB) && 4017c478bd9Sstevel@tonic-gate ((strcmp(_icache->c_name, 4027c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_SCN_SHSTR))) == 0)) 4037c478bd9Sstevel@tonic-gate _icache->c_flags = FLG_C_SHSTR; 4047c478bd9Sstevel@tonic-gate else if (flags & RTLD_STRIP) { 4057c478bd9Sstevel@tonic-gate _icache->c_flags = FLG_C_EXCLUDE; 4067c478bd9Sstevel@tonic-gate continue; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * Skip relocation sections for the time being, they'll be 4127c478bd9Sstevel@tonic-gate * analyzed after all sections have been processed. 4137c478bd9Sstevel@tonic-gate */ 4147c478bd9Sstevel@tonic-gate if ((shdr->sh_type == M_REL_SHT_TYPE) && shdr->sh_addr) 4157c478bd9Sstevel@tonic-gate continue; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* 4187c478bd9Sstevel@tonic-gate * Sections at this point will simply be passed through to the 4197c478bd9Sstevel@tonic-gate * output file. Keep track of the section header string table 4207c478bd9Sstevel@tonic-gate * size. 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate shstr_size += strlen(_icache->c_name) + 1; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * If a heap section is to be added to the output image, 4267c478bd9Sstevel@tonic-gate * indicate that it will be added following the last data 4277c478bd9Sstevel@tonic-gate * section. 4287c478bd9Sstevel@tonic-gate */ 4297c478bd9Sstevel@tonic-gate if (shdr->sh_addr && ((shdr->sh_addr + shdr->sh_size) == 4307c478bd9Sstevel@tonic-gate (data_phdr->p_vaddr + data_phdr->p_memsz))) { 4317c478bd9Sstevel@tonic-gate data_cache = _icache; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate if (status) { 4347c478bd9Sstevel@tonic-gate _icache++; 4357c478bd9Sstevel@tonic-gate _icache->c_name = 4367c478bd9Sstevel@tonic-gate (char *)MSG_ORIG(MSG_SCN_HEAP); 4377c478bd9Sstevel@tonic-gate _icache->c_flags = FLG_C_HEAP; 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate _icache->c_scn = 0; 4407c478bd9Sstevel@tonic-gate _icache->c_shdr = 0; 4417c478bd9Sstevel@tonic-gate _icache->c_data = 0; 4427c478bd9Sstevel@tonic-gate _icache->c_info = 0; 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate shstr_size += strlen(_icache->c_name) + 1; 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate /* 4507c478bd9Sstevel@tonic-gate * Now that we've processed all input sections count the relocation 4517c478bd9Sstevel@tonic-gate * entries (relocation sections need to reference their symbol tables). 4527c478bd9Sstevel@tonic-gate */ 4537c478bd9Sstevel@tonic-gate _icache = icache; 4547c478bd9Sstevel@tonic-gate for (_icache++; _icache->c_flags != FLG_C_END; _icache++) { 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate if ((shdr = _icache->c_shdr) == 0) 4577c478bd9Sstevel@tonic-gate continue; 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * If any form of relocations are to be applied to the output 4617c478bd9Sstevel@tonic-gate * image determine what relocation counts exist. These will be 4627c478bd9Sstevel@tonic-gate * used to reorganize (localize) the relocation records. 4637c478bd9Sstevel@tonic-gate */ 4647c478bd9Sstevel@tonic-gate if ((shdr->sh_type == M_REL_SHT_TYPE) && shdr->sh_addr) { 4657c478bd9Sstevel@tonic-gate rel_entsize = shdr->sh_entsize; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (count_reloc(icache, _icache, lmp, flags, addr, 4682926dd2eSrie &rel_null_no, &rel_data_no, &rel_func_no, 4692926dd2eSrie nodirect)) { 4707c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, 4717c478bd9Sstevel@tonic-gate fd, opath); 4727c478bd9Sstevel@tonic-gate return (1); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* 4787c478bd9Sstevel@tonic-gate * If any form of relocations are to be applied to the output image 4797c478bd9Sstevel@tonic-gate * then we will reorganize (localize) the relocation records. If this 4807c478bd9Sstevel@tonic-gate * reorganization occurs, the relocation sections will no longer have a 4817c478bd9Sstevel@tonic-gate * one-to-one relationship with the section they relocate, hence we 4827c478bd9Sstevel@tonic-gate * rename them to a more generic name. 4837c478bd9Sstevel@tonic-gate */ 4847c478bd9Sstevel@tonic-gate _icache = icache; 4857c478bd9Sstevel@tonic-gate for (_icache++; _icache->c_flags != FLG_C_END; _icache++) { 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate if ((shdr = _icache->c_shdr) == 0) 4887c478bd9Sstevel@tonic-gate continue; 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate if ((shdr->sh_type == M_REL_SHT_TYPE) && shdr->sh_addr) { 4917c478bd9Sstevel@tonic-gate if (rel_null_no) { 4927c478bd9Sstevel@tonic-gate _icache->c_flags = FLG_C_RELOC; 4937c478bd9Sstevel@tonic-gate _icache->c_name = 4947c478bd9Sstevel@tonic-gate (char *)MSG_ORIG(MSG_SCN_RELOC); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate shstr_size += strlen(_icache->c_name) + 1; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * If there is no data section, and a heap is required, warn the user 5037c478bd9Sstevel@tonic-gate * and disable the heap addition. 5047c478bd9Sstevel@tonic-gate */ 5057c478bd9Sstevel@tonic-gate if (!data_cache) { 5065aefb655Srie eprintf(lml, ERR_WARNING, MSG_INTL(MSG_IMG_DATASEC), ipath); 5077c478bd9Sstevel@tonic-gate status = 0; 5087c478bd9Sstevel@tonic-gate endx = 0; 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate /* 5127c478bd9Sstevel@tonic-gate * Determine the value of _edata (which will also be _end) and its 5137c478bd9Sstevel@tonic-gate * section index for updating the data segments phdr and symbol table 5147c478bd9Sstevel@tonic-gate * information later. If a new heap section is being added, update 5157c478bd9Sstevel@tonic-gate * the values appropriately. 5167c478bd9Sstevel@tonic-gate */ 5177c478bd9Sstevel@tonic-gate edata = data_phdr->p_vaddr + data_phdr->p_memsz; 5187c478bd9Sstevel@tonic-gate if (status) 5197c478bd9Sstevel@tonic-gate edata += status->pr_brksize; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate if (endx) { 5227c478bd9Sstevel@tonic-gate /* LINTED */ 5237c478bd9Sstevel@tonic-gate endx = (Half)elf_ndxscn(data_cache->c_scn); 5247c478bd9Sstevel@tonic-gate if (status) 5257c478bd9Sstevel@tonic-gate endx++; 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate /* 5297c478bd9Sstevel@tonic-gate * We're now ready to construct the new elf image. 5307c478bd9Sstevel@tonic-gate * 5317c478bd9Sstevel@tonic-gate * Obtain a new elf header and initialize it with any basic information 5327c478bd9Sstevel@tonic-gate * that isn't calculated as part of elf_update(). 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate if ((oehdr = elf_newehdr(oelf)) == NULL) { 5355aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_NEWEHDR), opath); 5367c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 5377c478bd9Sstevel@tonic-gate return (1); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate oehdr->e_machine = iehdr->e_machine; 5407c478bd9Sstevel@tonic-gate oehdr->e_flags = iehdr->e_flags; 5417c478bd9Sstevel@tonic-gate oehdr->e_type = ET_EXEC; 5427c478bd9Sstevel@tonic-gate oehdr->e_entry = iehdr->e_entry; 5437c478bd9Sstevel@tonic-gate if (addr) 5447c478bd9Sstevel@tonic-gate oehdr->e_entry += addr; 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate /* 5477c478bd9Sstevel@tonic-gate * Obtain a new set of program headers. Initialize these with the same 5487c478bd9Sstevel@tonic-gate * information as the input program headers. Update the virtual address 5497c478bd9Sstevel@tonic-gate * and the data segments size to reflect any new heap section. 5507c478bd9Sstevel@tonic-gate */ 5517c478bd9Sstevel@tonic-gate if ((ophdr = elf_newphdr(oelf, iehdr->e_phnum)) == NULL) { 5525aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_NEWPHDR), opath); 5537c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 5547c478bd9Sstevel@tonic-gate return (1); 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate for (num = 0; num != iehdr->e_phnum; num++, iphdr++, ophdr++) { 5577c478bd9Sstevel@tonic-gate *ophdr = *iphdr; 5587c478bd9Sstevel@tonic-gate if ((ophdr->p_type != PT_INTERP) && (ophdr->p_type != PT_NOTE)) 5597c478bd9Sstevel@tonic-gate ophdr->p_vaddr += addr; 5607c478bd9Sstevel@tonic-gate if (data_phdr == iphdr) { 5617c478bd9Sstevel@tonic-gate if (status) 5627c478bd9Sstevel@tonic-gate ophdr->p_memsz = edata - ophdr->p_vaddr; 5637c478bd9Sstevel@tonic-gate ophdr->p_filesz = ophdr->p_memsz; 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* 5687c478bd9Sstevel@tonic-gate * Establish a buffer for the new section header string table. This 5697c478bd9Sstevel@tonic-gate * will be filled in as each new section is created. 5707c478bd9Sstevel@tonic-gate */ 5717c478bd9Sstevel@tonic-gate if ((shstr = malloc(shstr_size)) == 0) { 5727c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 5737c478bd9Sstevel@tonic-gate return (1); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate _shstr = shstr; 5767c478bd9Sstevel@tonic-gate *_shstr++ = '\0'; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* 5797c478bd9Sstevel@tonic-gate * Use the input files cache information to generate new sections. 5807c478bd9Sstevel@tonic-gate */ 5817c478bd9Sstevel@tonic-gate _icache = icache; 5827c478bd9Sstevel@tonic-gate for (_icache++; _icache->c_flags != FLG_C_END; _icache++) { 5837c478bd9Sstevel@tonic-gate /* 5847c478bd9Sstevel@tonic-gate * Skip any excluded sections. 5857c478bd9Sstevel@tonic-gate */ 5867c478bd9Sstevel@tonic-gate if (_icache->c_flags == FLG_C_EXCLUDE) 5877c478bd9Sstevel@tonic-gate continue; 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate /* 5907c478bd9Sstevel@tonic-gate * Create a matching section header in the output file. 5917c478bd9Sstevel@tonic-gate */ 5927c478bd9Sstevel@tonic-gate if ((scn = elf_newscn(oelf)) == NULL) { 5935aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_NEWSCN), opath); 5947c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 5957c478bd9Sstevel@tonic-gate return (1); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate if ((shdr = elf_getshdr(scn)) == NULL) { 5985aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_NEWSHDR), opath); 5997c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 6007c478bd9Sstevel@tonic-gate return (1); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * If this is the heap section initialize the appropriate 6057c478bd9Sstevel@tonic-gate * entries, otherwise simply use the original section header 6067c478bd9Sstevel@tonic-gate * information. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate if (_icache->c_flags == FLG_C_HEAP) { 6097c478bd9Sstevel@tonic-gate shdr->sh_type = SHT_PROGBITS; 6107c478bd9Sstevel@tonic-gate shdr->sh_flags = SHF_ALLOC | SHF_WRITE; 6117c478bd9Sstevel@tonic-gate } else 6127c478bd9Sstevel@tonic-gate *shdr = *_icache->c_shdr; 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate /* 6157c478bd9Sstevel@tonic-gate * Create a matching data buffer for this section. 6167c478bd9Sstevel@tonic-gate */ 6177c478bd9Sstevel@tonic-gate if ((data = elf_newdata(scn)) == NULL) { 6185aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_NEWDATA), opath); 6197c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 6207c478bd9Sstevel@tonic-gate return (1); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* 6247c478bd9Sstevel@tonic-gate * Determine what data will be used for this section. 6257c478bd9Sstevel@tonic-gate */ 6267c478bd9Sstevel@tonic-gate if (_icache->c_flags == FLG_C_SHSTR) { 6277c478bd9Sstevel@tonic-gate /* 6287c478bd9Sstevel@tonic-gate * Reassign the shstrtab to the new data buffer we're 6297c478bd9Sstevel@tonic-gate * creating. Insure that the new elf header references 6307c478bd9Sstevel@tonic-gate * this section header table. 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate *data = *_icache->c_data; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate data->d_buf = (void *)shstr; 6357c478bd9Sstevel@tonic-gate data->d_size = shstr_size; 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate _icache->c_info = shstr; 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate /* LINTED */ 640*e4096c82SRichard Lowe if (elf_ndxscn(scn) >= SHN_LORESERVE) { 641*e4096c82SRichard Lowe Elf_Scn *_scn; 642*e4096c82SRichard Lowe Shdr *shdr0; 643*e4096c82SRichard Lowe 644*e4096c82SRichard Lowe /* 645*e4096c82SRichard Lowe * libelf deals with e_shnum for us, but we 646*e4096c82SRichard Lowe * need to deal with e_shstrndx ourselves. 647*e4096c82SRichard Lowe */ 648*e4096c82SRichard Lowe oehdr->e_shstrndx = SHN_XINDEX; 649*e4096c82SRichard Lowe if ((_scn = elf_getscn(oelf, 0)) == NULL) { 650*e4096c82SRichard Lowe eprintf(lml, ERR_ELF, 651*e4096c82SRichard Lowe MSG_ORIG(MSG_ELF_GETSCN), opath); 652*e4096c82SRichard Lowe cleanup(ielf, oelf, melf, icache, 653*e4096c82SRichard Lowe mcache, fd, opath); 654*e4096c82SRichard Lowe return (1); 655*e4096c82SRichard Lowe } 656*e4096c82SRichard Lowe shdr0 = elf_getshdr(_scn); 657*e4096c82SRichard Lowe shdr0->sh_link = elf_ndxscn(scn); 658*e4096c82SRichard Lowe } else { 6597c478bd9Sstevel@tonic-gate oehdr->e_shstrndx = (Half)elf_ndxscn(scn); 660*e4096c82SRichard Lowe } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate } else if (_icache->c_flags == FLG_C_HEAP) { 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * Assign the heap to the appropriate memory offset. 6657c478bd9Sstevel@tonic-gate */ 6667c478bd9Sstevel@tonic-gate data->d_buf = status->pr_brkbase; 6677c478bd9Sstevel@tonic-gate data->d_type = ELF_T_BYTE; 6687c478bd9Sstevel@tonic-gate data->d_size = (size_t)status->pr_brksize; 6697c478bd9Sstevel@tonic-gate data->d_off = 0; 6707c478bd9Sstevel@tonic-gate data->d_align = 1; 6717c478bd9Sstevel@tonic-gate data->d_version = EV_CURRENT; 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate shdr->sh_addr = data_cache->c_shdr->sh_addr + 6747c478bd9Sstevel@tonic-gate data_cache->c_shdr->sh_size; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate } else if (_icache->c_flags == FLG_C_RELOC) { 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * If some relocations are to be saved in the new image 6797c478bd9Sstevel@tonic-gate * then the relocation sections will be reorganized to 6807c478bd9Sstevel@tonic-gate * localize their contents. These relocation sections 6817c478bd9Sstevel@tonic-gate * will no longer have a one-to-one relationship with 6827c478bd9Sstevel@tonic-gate * the section they relocate, hence we rename them and 6837c478bd9Sstevel@tonic-gate * remove their sh_info info. 6847c478bd9Sstevel@tonic-gate */ 6857c478bd9Sstevel@tonic-gate *data = *_icache->c_data; 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate shdr->sh_info = 0; 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate } else { 6907c478bd9Sstevel@tonic-gate /* 6917c478bd9Sstevel@tonic-gate * By default simply pass the section through. If 6927c478bd9Sstevel@tonic-gate * we've been asked to use the memory image of the 6937c478bd9Sstevel@tonic-gate * input file reestablish the data buffer address. 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate *data = *_icache->c_data; 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate if ((shdr->sh_addr) && (flags & RTLD_MEMORY)) 6987c478bd9Sstevel@tonic-gate data->d_buf = (void *)(shdr->sh_addr + addr); 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* 7017c478bd9Sstevel@tonic-gate * Update any NOBITS section to indicate that it now 7027c478bd9Sstevel@tonic-gate * contains data. If this image is being created 7037c478bd9Sstevel@tonic-gate * directly from the input file, zero out the .bss 7047c478bd9Sstevel@tonic-gate * section (this saves ld.so.1 having to zero out memory 7057c478bd9Sstevel@tonic-gate * or do any /dev/zero mappings). 7067c478bd9Sstevel@tonic-gate */ 7077c478bd9Sstevel@tonic-gate if (shdr->sh_type == SHT_NOBITS) { 7087c478bd9Sstevel@tonic-gate shdr->sh_type = SHT_PROGBITS; 7097c478bd9Sstevel@tonic-gate if (!(flags & RTLD_MEMORY)) { 7107c478bd9Sstevel@tonic-gate if ((data->d_buf = calloc(1, 7117c478bd9Sstevel@tonic-gate data->d_size)) == 0) { 7127c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, 7137c478bd9Sstevel@tonic-gate icache, mcache, fd, opath); 7147c478bd9Sstevel@tonic-gate return (1); 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate /* 7217c478bd9Sstevel@tonic-gate * Update the section header string table. 7227c478bd9Sstevel@tonic-gate */ 7237c478bd9Sstevel@tonic-gate /* LINTED */ 7247c478bd9Sstevel@tonic-gate shdr->sh_name = (Word)(_shstr - shstr); 7257c478bd9Sstevel@tonic-gate (void) strcpy(_shstr, _icache->c_name); 7267c478bd9Sstevel@tonic-gate _shstr = _shstr + strlen(_icache->c_name) + 1; 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate /* 7297c478bd9Sstevel@tonic-gate * For each section that has a virtual address update its 7307c478bd9Sstevel@tonic-gate * address to the fixed location of the new image. 7317c478bd9Sstevel@tonic-gate */ 7327c478bd9Sstevel@tonic-gate if (shdr->sh_addr) 7337c478bd9Sstevel@tonic-gate shdr->sh_addr += addr; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * If we've inserted a new section any later sections may need 7377c478bd9Sstevel@tonic-gate * their sh_link fields updated (.stabs comes to mind). 7387c478bd9Sstevel@tonic-gate */ 7397c478bd9Sstevel@tonic-gate if (status && endx && (shdr->sh_link >= endx)) 7407c478bd9Sstevel@tonic-gate shdr->sh_link++; 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* 7447c478bd9Sstevel@tonic-gate * Generate the new image, and obtain a new elf descriptor that will 7457c478bd9Sstevel@tonic-gate * allow us to write and update the new image. 7467c478bd9Sstevel@tonic-gate */ 7477c478bd9Sstevel@tonic-gate if (elf_update(oelf, ELF_C_WRIMAGE) == -1) { 7485aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_UPDATE), opath); 7497c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 7507c478bd9Sstevel@tonic-gate return (1); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate if ((melf = elf_begin(0, ELF_C_IMAGE, oelf)) == NULL) { 7535aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_BEGIN), opath); 7547c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 7557c478bd9Sstevel@tonic-gate return (1); 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate if ((mehdr = elf_getehdr(melf)) == NULL) { 7585aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETEHDR), opath); 7597c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 7607c478bd9Sstevel@tonic-gate return (1); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate 763*e4096c82SRichard Lowe if (elf_getshdrnum(melf, &shndx) == -1) { 764*e4096c82SRichard Lowe eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSHDRNUM), opath); 765*e4096c82SRichard Lowe cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 766*e4096c82SRichard Lowe return (1); 767*e4096c82SRichard Lowe } 768*e4096c82SRichard Lowe 7697c478bd9Sstevel@tonic-gate /* 7707c478bd9Sstevel@tonic-gate * Construct a cache to maintain the memory files section information. 7717c478bd9Sstevel@tonic-gate */ 772*e4096c82SRichard Lowe if ((mcache = calloc(shndx, sizeof (Cache))) == 0) { 7737c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 7747c478bd9Sstevel@tonic-gate return (1); 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate _mcache = mcache; 7777c478bd9Sstevel@tonic-gate _mcache++; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate for (scn = 0; scn = elf_nextscn(melf, scn); _mcache++) { 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate if ((_mcache->c_shdr = elf_getshdr(scn)) == NULL) { 7825aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSHDR), opath); 7837c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 7847c478bd9Sstevel@tonic-gate return (1); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate if ((_mcache->c_data = elf_getdata(scn, NULL)) == NULL) { 7885aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETDATA), opath); 7897c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 7907c478bd9Sstevel@tonic-gate return (1); 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate } 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate /* 7957c478bd9Sstevel@tonic-gate * Now that we have a complete description of the new image update any 7967c478bd9Sstevel@tonic-gate * sections that are required. 7977c478bd9Sstevel@tonic-gate * 7987c478bd9Sstevel@tonic-gate * o reset any symbol table entries. 7997c478bd9Sstevel@tonic-gate * 8007c478bd9Sstevel@tonic-gate * o reset any relocation entries. 8017c478bd9Sstevel@tonic-gate * 8027c478bd9Sstevel@tonic-gate * o reset dynamic entries. 8037c478bd9Sstevel@tonic-gate */ 8047c478bd9Sstevel@tonic-gate _mcache = &mcache[0]; 8057c478bd9Sstevel@tonic-gate for (_icache = &icache[1]; _icache->c_flags != FLG_C_END; _icache++) { 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate if (_icache->c_flags == FLG_C_EXCLUDE) 8087c478bd9Sstevel@tonic-gate continue; 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate _mcache++; 8117c478bd9Sstevel@tonic-gate shdr = _mcache->c_shdr; 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate /* 8147c478bd9Sstevel@tonic-gate * Update the symbol table entries. _end and _edata will be 8157c478bd9Sstevel@tonic-gate * changed to reflect any heap addition. All global symbols 8167c478bd9Sstevel@tonic-gate * will be updated to their new fixed address. 8177c478bd9Sstevel@tonic-gate */ 8187c478bd9Sstevel@tonic-gate if ((shdr->sh_type == SHT_SYMTAB) || 81975e45495Sab196087 (shdr->sh_type == SHT_DYNSYM) || 82075e45495Sab196087 (shdr->sh_type == SHT_SUNW_LDYNSYM)) { 8217c478bd9Sstevel@tonic-gate update_sym(mcache, _mcache, edata, endx, addr); 8227c478bd9Sstevel@tonic-gate continue; 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * Update any relocations. All relocation requirements will 8277c478bd9Sstevel@tonic-gate * have been established in count_reloc(). 8287c478bd9Sstevel@tonic-gate */ 8297c478bd9Sstevel@tonic-gate if (shdr->sh_type == M_REL_SHT_TYPE) { 8307c478bd9Sstevel@tonic-gate if (rel_base == (Rel *)0) { 8317c478bd9Sstevel@tonic-gate rel_base = (Rel *)_mcache->c_data->d_buf; 8327c478bd9Sstevel@tonic-gate rel_null = rel_base; 8337c478bd9Sstevel@tonic-gate rel_data = (Rel *)((Xword)rel_null + 8347c478bd9Sstevel@tonic-gate (rel_null_no * rel_entsize)); 8357c478bd9Sstevel@tonic-gate rel_func = (Rel *)((Xword)rel_data + 8367c478bd9Sstevel@tonic-gate (rel_data_no * rel_entsize)); 8377c478bd9Sstevel@tonic-gate } 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate update_reloc(mcache, icache, _icache, opath, lmp, 8407c478bd9Sstevel@tonic-gate &rel_null, &rel_data, &rel_func); 8417c478bd9Sstevel@tonic-gate continue; 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate /* 8457c478bd9Sstevel@tonic-gate * Perform any dynamic entry updates after all relocation 8467c478bd9Sstevel@tonic-gate * processing has been carried out (as its possible the .dynamic 8477c478bd9Sstevel@tonic-gate * section could occur before the .rel sections, delay this 8487c478bd9Sstevel@tonic-gate * processing until last). 8497c478bd9Sstevel@tonic-gate */ 8507c478bd9Sstevel@tonic-gate if (shdr->sh_type == SHT_DYNAMIC) 8517c478bd9Sstevel@tonic-gate dyn_cache = _mcache; 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate if (dyn_cache) { 8557c478bd9Sstevel@tonic-gate Xword off = (Xword)rel_base - (Xword)mehdr; 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate /* 8587c478bd9Sstevel@tonic-gate * If we're dumping a fixed object (typically the dynamic 8597c478bd9Sstevel@tonic-gate * executable) compensate for its real base address. 8607c478bd9Sstevel@tonic-gate */ 8617c478bd9Sstevel@tonic-gate if (!addr) 8627c478bd9Sstevel@tonic-gate off += ADDR(lmp); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate if (update_dynamic(mcache, dyn_cache, lmp, flags, addr, off, 8657c478bd9Sstevel@tonic-gate opath, rel_null_no, rel_data_no, rel_func_no, rel_entsize, 8667c478bd9Sstevel@tonic-gate elf_checksum(melf))) { 8677c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 8687c478bd9Sstevel@tonic-gate return (1); 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * Having completed all section updates write the memory file out. 8747c478bd9Sstevel@tonic-gate */ 8757c478bd9Sstevel@tonic-gate if (elf_update(oelf, ELF_C_WRITE) == -1) { 8765aefb655Srie eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_UPDATE), opath); 8777c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, opath); 8787c478bd9Sstevel@tonic-gate return (1); 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate cleanup(ielf, oelf, melf, icache, mcache, fd, 0); 8827c478bd9Sstevel@tonic-gate return (0); 8837c478bd9Sstevel@tonic-gate } 884