1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #include <string.h> 31 #include <ar.h> 32 #include <stdlib.h> 33 #include <sys/mman.h> 34 #include <errno.h> 35 #include <libelf.h> 36 #include "decl.h" 37 #include "member.h" 38 #include "msg.h" 39 40 #include <sys/mman.h> 41 42 /* 43 * Cook the input file. 44 * These functions take the input file buffer and extract 45 * the Ehdr, Phdr table, and the Shdr table. They keep track 46 * of the buffer status as "fresh," "cooked," or "frozen." 47 * 48 * fresh The file buffer is in its original state and 49 * nothing has yet referenced it. 50 * 51 * cooked The application asked for translated data first 52 * and caused the library to return a pointer into 53 * the file buffer. After this happens, all "raw" 54 * operations must go back to the disk. 55 * 56 * frozen The application first did a "raw" operation that 57 * prohibits reusing the file buffer. This effectively 58 * freezes the buffer, and all "normal" operations must 59 * duplicate their data. 60 * 61 * For archive handling, these functions conspire to align the 62 * file buffer to the host memory format. Archive members 63 * are guaranteed only even byte alignment, but the file uses 64 * objects at least 4 bytes long. If an archive member is about 65 * to be cooked and is not aligned in memory, these functions 66 * "slide" the buffer up into the archive member header. 67 * This sliding never occurs for frozen files. 68 * 69 * Some processors might not need sliding at all, if they have 70 * no alignment constraints on memory references. This code 71 * ignores that possibility for two reasons. First, even machines 72 * that have no constraints usually handle aligned objects faster 73 * than unaligned. Forcing alignment here probably leads to better 74 * performance. Second, there's no way to test at run time whether 75 * alignment is required or not. The safe thing is to align in 76 * all cases. 77 * 78 * This sliding relies on the archive header being disposable. 79 * Only archive members that are object files ever slide. 80 * They're also the only ones that ever need to. Archives never 81 * freeze to make headers disposable. Any program peculiar enough 82 * to want a frozen archive pays the penalty. 83 * 84 * The library itself inspects the Ehdr and the Shdr table 85 * from the file. Consequently, it converts the file's data 86 * to EV_CURRENT version, not the working version. This is 87 * transparent to the user. The library never looks at the 88 * Phdr table; so that's kept in the working version. 89 */ 90 91 Dnode * 92 _elf_dnode() 93 { 94 register Dnode *d; 95 96 if ((d = (Dnode *)malloc(sizeof (Dnode))) == 0) { 97 _elf_seterr(EMEM_DNODE, errno); 98 return (0); 99 } 100 *d = _elf_dnode_init; 101 d->db_myflags = DBF_ALLOC; 102 return (d); 103 } 104 105 106 107 int 108 _elf_slide(Elf * elf) 109 { 110 Elf *par = elf->ed_parent; 111 size_t sz, szof; 112 register char *dst; 113 register char *src = elf->ed_ident; 114 115 if (par == 0 || par->ed_kind != ELF_K_AR) 116 return (0); 117 118 /* 119 * This code relies on other code to ensure 120 * the ar_hdr is big enough to move into. 121 */ 122 if (elf->ed_ident[EI_CLASS] == ELFCLASS64) 123 szof = sizeof (Elf64); 124 else 125 szof = sizeof (Elf32); 126 if ((sz = (size_t)(src - (char *)elf->ed_image) % szof) == 0) 127 return (0); 128 dst = src - sz; 129 elf->ed_ident -= sz; 130 elf->ed_memoff -= sz; 131 elf->ed_armem->m_slide = sz; 132 if (_elf_vm(par, elf->ed_memoff, sz + elf->ed_fsz) != OK_YES) 133 return (-1); 134 135 /* 136 * If the archive has been mmaped in, and we're going to slide it, 137 * and it wasn't open for write in the first place, and we've never 138 * done the mprotect() operation before, then do it now. 139 */ 140 if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) && 141 ((elf->ed_myflags & EDF_MPROTECT) == 0)) { 142 if (mprotect((char *)elf->ed_image, elf->ed_imagesz, 143 PROT_READ|PROT_WRITE) == -1) { 144 _elf_seterr(EIO_VM, errno); 145 return (-1); 146 } 147 elf->ed_myflags |= EDF_MPROTECT; 148 } 149 150 if (memmove((void *)dst, (const void *)src, elf->ed_fsz) != (void *)dst) 151 return (-1); 152 else 153 return (0); 154 } 155 156 157 Okay 158 _elf_cook(Elf * elf) 159 { 160 register int inplace = 1; 161 162 if (elf->ed_kind != ELF_K_ELF) 163 return (OK_YES); 164 165 if ((elf->ed_status == ES_COOKED) || 166 ((elf->ed_myflags & EDF_READ) == 0)) 167 return (OK_YES); 168 169 /* 170 * Here's where the unaligned archive member gets fixed. 171 */ 172 if (elf->ed_status == ES_FRESH && _elf_slide(elf) != 0) 173 return (OK_NO); 174 175 if (elf->ed_status == ES_FROZEN) 176 inplace = 0; 177 178 /* 179 * This is the first time we've actually looked at the file 180 * contents. We need to know whether or not this is an 181 * Elf32 or Elf64 file before we can decode the header. 182 * But it's the header that tells us which is which. 183 * 184 * Resolve the chicken-and-egg problem by peeking at the 185 * 'class' byte in the ident string. 186 */ 187 if (elf->ed_ident[EI_CLASS] == ELFCLASS32) { 188 if (_elf32_ehdr(elf, inplace) != 0) 189 return (OK_NO); 190 if (_elf32_phdr(elf, inplace) != 0) 191 goto xehdr; 192 if (_elf32_shdr(elf, inplace) != 0) 193 goto xphdr; 194 elf->ed_class = ELFCLASS32; 195 } else if (elf->ed_ident[EI_CLASS] == ELFCLASS64) { 196 if (_elf64_ehdr(elf, inplace) != 0) 197 return (OK_NO); 198 if (_elf64_phdr(elf, inplace) != 0) 199 goto xehdr; 200 if (_elf64_shdr(elf, inplace) != 0) 201 goto xphdr; 202 elf->ed_class = ELFCLASS64; 203 } else 204 return (OK_NO); 205 206 return (OK_YES); 207 208 xphdr: 209 if (elf->ed_myflags & EDF_PHALLOC) { 210 elf->ed_myflags &= ~EDF_PHALLOC; 211 free(elf->ed_phdr); 212 } 213 elf->ed_phdr = 0; 214 xehdr: 215 if (elf->ed_myflags & EDF_EHALLOC) { 216 elf->ed_myflags &= ~EDF_EHALLOC; 217 free(elf->ed_ehdr); 218 } 219 elf->ed_ehdr = 0; 220 221 return (OK_NO); 222 } 223 224 225 Okay 226 _elf_cookscn(Elf_Scn * s) 227 { 228 Elf * elf = s->s_elf; 229 230 if (elf->ed_class == ELFCLASS32) { 231 return (_elf32_cookscn(s)); 232 } else if (elf->ed_class == ELFCLASS64) { 233 return (_elf64_cookscn(s)); 234 } 235 236 _elf_seterr(EREQ_CLASS, 0); 237 return (OK_NO); 238 } 239