1/* Unexec for Sunos 4 using shared libraries. 2 Copyright (C) 1990, 1994, 1999, 2001, 2002, 2003, 2004, 3 2005, 2006, 2007 Free Software Foundation, Inc. 4 5This file is part of GNU Emacs. 6 7GNU Emacs is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2, or (at your option) 10any later version. 11 12GNU Emacs is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with GNU Emacs; see the file COPYING. If not, write to 19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20Boston, MA 02110-1301, USA. */ 21 22/* Contributed by Viktor Dukhovni. */ 23/* 24 * Unexec for Berkeley a.out format + SUNOS shared libraries 25 * The unexeced executable contains the __DYNAMIC area from the 26 * original text file, and then the rest of data + bss + malloced area of 27 * the current process. (The __DYNAMIC area is at the top of the process 28 * data segment, we use "data_start" defined externally to mark the start 29 * of the "real" data segment.) 30 * 31 * For programs that want to remap some of the data segment read only 32 * a run_time_remap is provided. This attempts to remap largest area starting 33 * and ending on page boundaries between "data_start" and "bndry" 34 * For this it to figure out where the text file is located. A path search 35 * is attempted after trying argv[0] and if all fails we simply do not remap 36 * 37 * One feature of run_time_remap () is mandatory: reseting the break. 38 * 39 * Note that we can no longer map data into the text segment, as this causes 40 * the __DYNAMIC struct to become read only, breaking the runtime loader. 41 * Thus we no longer need to mess with a private crt0.c, the standard one 42 * will do just fine, since environ can live in the writable area between 43 * __DYNAMIC and data_start, just make sure that pre-crt0.o (the name 44 * is somewhat abused here) is loaded first! 45 * 46 */ 47 48#ifdef emacs 49#include <config.h> 50#endif 51 52#include <sys/param.h> 53#include <sys/mman.h> 54#include <sys/file.h> 55#include <sys/stat.h> 56#include <string.h> 57#include <stdio.h> 58#include <a.out.h> 59 60#if defined (SUNOS4) || defined (__FreeBSD__) || defined (__NetBSD__) 61#define UNDO_RELOCATION 62#endif 63 64#ifdef UNDO_RELOCATION 65#include <link.h> 66#endif 67 68#ifdef HAVE_UNISTD_H 69#include <unistd.h> 70#endif 71 72/* NetBSD needs this bit, but SunOS does not have it. */ 73#ifndef MAP_FILE 74#define MAP_FILE 0 75#endif 76 77 78/* 79 * for programs other than emacs 80 * define data_start + initialized here, and make sure 81 * this object is loaded first! 82 * emacs will define these elsewhere, and load the object containing 83 * data_start (pre-crt0.o or firstfile.o?) first! 84 * The custom crt0.o *must not* be loaded! 85 */ 86#ifndef emacs 87 static int data_start = 0; 88 static int initialized = 0; 89#else 90 extern int initialized; 91 extern unsigned data_start; 92 extern int pureptr; 93#endif 94 95extern char *getenv (); 96static unsigned brk_value; 97static struct exec nhdr; 98static int rd_only_len; 99static long cookie; 100 101 102unexec (new_name, a_name, bndry, bss_start, entry) 103 char *new_name, *a_name; 104 unsigned bndry, bss_start, entry; 105{ 106 int fd, new; 107 char *old; 108 struct exec ohdr; /* Allocate on the stack, not needed in the next life */ 109 struct stat stat; 110 111 if ((fd = open (a_name, O_RDONLY)) < 0) 112 { 113 fprintf (stderr, "%s: open: ", a_name); 114 perror (a_name); 115 exit (1); 116 } 117 if ((new = open (new_name, O_WRONLY | O_CREAT, 0666)) == -1) 118 { 119 fprintf (stderr, "%s: open: ", a_name); 120 perror (new_name); 121 exit (1); 122 } 123 124 if ((fstat (fd, &stat) == -1)) 125 { 126 fprintf (stderr, "%s: ", a_name); 127 perror ("fstat"); 128 exit (1); 129 } 130 131 old = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0); 132 if (old == (char *)-1) 133 { 134 fprintf (stderr, "%s: ", a_name); 135 perror ("mmap"); 136 exit (1); 137 } 138 close (fd); 139 140 nhdr = ohdr = (*(struct exec *)old); 141 142 143 /* 144 * Remember a magic cookie so we know we've got the right binary 145 * when remapping. 146 */ 147 cookie = time (0); 148 149 /* Save the break, it is reset to &_end (by ld.so?). */ 150 brk_value = (unsigned) sbrk (0); 151 152 /* 153 * Round up data start to a page boundary (Lose if not a 2 power!) 154 */ 155 data_start = ((((int)&data_start) - 1) & ~(N_PAGSIZ (nhdr) - 1)) + N_PAGSIZ (nhdr); 156 157 /* 158 * Round down read only pages to a multiple of the page size 159 */ 160 if (bndry) 161 rd_only_len = ((int)bndry & ~(N_PAGSIZ (nhdr) - 1)) - data_start; 162 163#ifndef emacs 164 /* Have to do this some time before dumping the data */ 165 initialized = 1; 166#endif 167 168 /* Handle new data and bss sizes and optional new entry point. 169 No one actually uses bss_start and entry, but tradition compels 170 one to support them. 171 Could complain if bss_start > brk_value, 172 but the caller is *supposed* to know what she is doing. */ 173 nhdr.a_data = (bss_start ? bss_start : brk_value) - N_DATADDR (nhdr); 174 nhdr.a_bss = bss_start ? brk_value - bss_start : 0; 175 if (entry) 176 nhdr.a_entry = entry; 177 178 /* 179 * Write out the text segment with new header 180 * Dynamic executables are ZMAGIC with N_TXTOFF==0 and the header 181 * part of the text segment, but no need to rely on this. 182 * So write the TEXT first, then go back replace the header. 183 * Doing it in the other order is less general! 184 */ 185 lseek (new, N_TXTOFF (nhdr), L_SET); 186 write (new, old + N_TXTOFF (ohdr), N_TXTOFF (ohdr) + ohdr.a_text); 187 lseek (new, 0L, L_SET); 188 write (new, &nhdr, sizeof (nhdr)); 189 190 /* 191 * Write out the head of the old data segment from the file not 192 * from core, this has the unresolved __DYNAMIC relocation data 193 * we need to reload 194 */ 195 lseek (new, N_DATOFF (nhdr), L_SET); 196 write (new, old + N_DATOFF (ohdr), (int)&data_start - N_DATADDR (ohdr)); 197 198 /* 199 * Copy the rest of the data from core 200 */ 201 write (new, &data_start, N_BSSADDR (nhdr) - (int)&data_start); 202 203 /* 204 * Copy the symbol table and line numbers 205 */ 206 lseek (new, N_TRELOFF (nhdr), L_SET); 207 write (new, old + N_TRELOFF (ohdr), stat.st_size - N_TRELOFF (ohdr)); 208 209 /* Some other BSD systems use this file. 210 We don't know whether this change is right for them. */ 211#ifdef UNDO_RELOCATION 212 /* Undo the relocations done at startup by ld.so. 213 It will do these relocations again when we start the dumped Emacs. 214 Doing them twice gives incorrect results. */ 215 { 216 unsigned long daddr = N_DATADDR (ohdr); 217 unsigned long rel, erel; 218#ifdef SUNOS4 219#ifdef SUNOS4_SHARED_LIBRARIES 220 extern struct link_dynamic _DYNAMIC; 221 222 /* SunOS4.x's ld_rel is relative to N_TXTADDR. */ 223 if (!ohdr.a_dynamic) 224 /* This was statically linked. */ 225 rel = erel = 0; 226 else if (_DYNAMIC.ld_version < 2) 227 { 228 rel = _DYNAMIC.ld_un.ld_1->ld_rel + N_TXTADDR (ohdr); 229 erel = _DYNAMIC.ld_un.ld_1->ld_hash + N_TXTADDR (ohdr); 230 } 231 else 232 { 233 rel = _DYNAMIC.ld_un.ld_2->ld_rel + N_TXTADDR (ohdr); 234 erel = _DYNAMIC.ld_un.ld_2->ld_hash + N_TXTADDR (ohdr); 235 } 236#else /* not SUNOS4_SHARED_LIBRARIES */ 237 rel = erel = 0; 238#endif /* not SUNOS4_SHARED_LIBRARIES */ 239#ifdef sparc 240#define REL_INFO_TYPE struct reloc_info_sparc 241#else 242#define REL_INFO_TYPE struct relocation_info 243#endif /* sparc */ 244#define REL_TARGET_ADDRESS(r) (((REL_INFO_TYPE *)(r))->r_address) 245#endif /* SUNOS4 */ 246#if defined (__FreeBSD__) || defined (__NetBSD__) 247 extern struct _dynamic _DYNAMIC; 248 249 /* FreeBSD's LD_REL is a virtual address itself. */ 250 rel = LD_REL (&_DYNAMIC); 251 erel = rel + LD_RELSZ (&_DYNAMIC); 252#define REL_INFO_TYPE struct relocation_info 253#define REL_TARGET_ADDRESS(r) (((REL_INFO_TYPE *)(r))->r_address) 254#endif 255 256 for (; rel < erel; rel += sizeof (REL_INFO_TYPE)) 257 { 258 /* This is the virtual address where ld.so will do relocation. */ 259 unsigned long target = REL_TARGET_ADDRESS (rel); 260 /* This is the offset in the data segment. */ 261 unsigned long segoffset = target - daddr; 262 263 /* If it is located below data_start, we have to do nothing here, 264 because the old data has been already written to the location. */ 265 if (target < (unsigned long)&data_start) 266 continue; 267 268 lseek (new, N_DATOFF (nhdr) + segoffset, L_SET); 269 write (new, old + N_DATOFF (ohdr) + segoffset, sizeof (unsigned long)); 270 } 271 } 272#endif /* UNDO_RELOCATION */ 273 274 fchmod (new, 0755); 275} 276 277void 278run_time_remap (progname) 279 char *progname; 280{ 281 char aout[MAXPATHLEN]; 282 register char *path, *p; 283 284 /* Just in case */ 285 if (!initialized) 286 return; 287 288 /* Restore the break */ 289 brk ((char *) brk_value); 290 291 /* If nothing to remap: we are done! */ 292 if (rd_only_len == 0) 293 return; 294 295 /* 296 * Attempt to find the executable 297 * First try argv[0], will almost always succeed as shells tend to give 298 * the full path from the hash list rather than using execvp () 299 */ 300 if (is_it (progname)) 301 return; 302 303 /* 304 * If argv[0] is a full path and does not exist, not much sense in 305 * searching further 306 */ 307 if (strchr (progname, '/')) 308 return; 309 310 /* 311 * Try to search for argv[0] on the PATH 312 */ 313 path = getenv ("PATH"); 314 if (path == NULL) 315 return; 316 317 while (*path) 318 { 319 /* copy through ':' or end */ 320 for (p = aout; *p = *path; ++p, ++path) 321 if (*p == ':') 322 { 323 ++path; /* move past ':' */ 324 break; 325 } 326 *p++ = '/'; 327 strcpy (p, progname); 328 /* 329 * aout is a candidate full path name 330 */ 331 if (is_it (aout)) 332 return; 333 } 334} 335 336is_it (filename) 337 char *filename; 338{ 339 int fd; 340 long filenames_cookie; 341 struct exec hdr; 342 343 /* 344 * Open an executable and check for a valid header! 345 * Can't bcmp the header with what we had, it may have been stripped! 346 * so we may save looking at non executables with the same name, mostly 347 * directories. 348 */ 349 fd = open (filename, O_RDONLY); 350 if (fd != -1) 351 { 352 if (read (fd, &hdr, sizeof (hdr)) == sizeof (hdr) 353 && !N_BADMAG (hdr) && N_DATOFF (hdr) == N_DATOFF (nhdr) 354 && N_TRELOFF (hdr) == N_TRELOFF (nhdr)) 355 { 356 /* compare cookies */ 357 lseek (fd, N_DATOFF (hdr) + (int)&cookie - N_DATADDR (hdr), L_SET); 358 read (fd, &filenames_cookie, sizeof (filenames_cookie)); 359 if (filenames_cookie == cookie) 360 { /* Eureka */ 361 362 /* 363 * Do the mapping 364 * The PROT_EXEC may not be needed, but it is safer this way. 365 * should the shared library decide to indirect through 366 * addresses in the data segment not part of __DYNAMIC 367 */ 368 mmap ((char *) data_start, rd_only_len, PROT_READ | PROT_EXEC, 369 MAP_FILE | MAP_SHARED | MAP_FIXED, fd, 370 N_DATOFF (hdr) + data_start - N_DATADDR (hdr)); 371 close (fd); 372 return 1; 373 } 374 } 375 close (fd); 376 } 377 return 0; 378} 379 380/* arch-tag: 30227420-2c6f-4700-a4f8-9e45e52f53b1 381 (do not change this comment) */ 382