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