1 /* Code to do an unexec for Sun O/S 4.1 for a temacs linked -Bdynamic.
2 Copyright (C) 1992, 1993 Free Software Foundation, Inc.
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Synched up with: Not synched with FSF. */
24 Created 29-Oct-92 by Harlan Sexton
25 Tweaked 06-Aug-93 by Dean Michaels to work with sun3.
28 /********************** Included .h Files **************************/
32 /* I don't understand this, but it's necessary to get some slots in struct exec
33 from /usr/include/sys/exec.h when running LCC in strict ANSI mode. We don't
34 need this in K&R mode...
36 #if defined(__lucid) && defined(__sparc) && !defined(sun)
41 #include <sys/param.h>
45 #include <sys/types.h>
55 /********************** Macros *************************************/
58 ((errno > 0)?((errno < sys_nerr)?(sys_errlist[errno]):\
59 "unknown system error"): "unknown error")
61 #define MASK_UP(x,p_of_two) \
62 ((((unsigned long) (x)) + ((p_of_two) - 1)) & (~((p_of_two) - 1)))
64 #define MASK_DOWN(x,p_of_two) (((unsigned long) (x)) & (~((p_of_two) - 1)))
67 #define relocation_info reloc_info_sparc
70 /********************** Typedefs and Structs ***********************/
72 struct translation_struct
81 /********************** Function Prototypes/Declarations ***********/
83 static void unexec_error (const char *m, int use_errno, ...);
84 static int unexec_open (char *filename, int flag, int mode);
85 static caddr_t unexec_mmap (int fd, size_t len, int prot, int flags);
86 static long unexec_seek (int fd, long position);
87 static void unexec_read (int fd, long position, char *buf, int bytes);
88 static void unexec_write (int fd, long position, char *buf, int bytes);
89 static void unexec_pad (int fd, int bytes);
90 static void unexec_fstat (int fd, struct stat *statptr);
91 static void unexec_fchmod (int fd, int mode);
92 static long unexec_addr_to_offset (long addr, struct translation_struct *ts);
93 static void copy_relocation_site (struct relocation_info *ri,
94 caddr_t from_base_addr,
96 struct translation_struct *ts);
97 static void reset_symtab (struct nlist *start, struct nlist *end,
98 char *strtab, long edata_value, long end_value,
99 int ld_so_table, int shlib_image);
100 int run_time_remap (char *dummy);
102 /********************** Variables **********************************/
104 /* for reporting error messages from system calls */
106 extern char *sys_errlist[];
109 extern char **environ;
111 static unsigned long mprotect_bottom_addr;
112 static unsigned long mprotect_top_addr;
114 static unsigned long sbrk_of_0_at_unexec;
116 /*******************************************************************/
119 unexec_error (const char *fmt, int use_errno, ...)
121 const char *err_msg = SYS_ERR;
124 fprintf (stderr, "unexec - ");
125 va_start (args, use_errno);
126 vfprintf (stderr, fmt, args);
130 fprintf (stderr, ": %s", err_msg);
131 fprintf (stderr, "\n");
137 unexec_open (char *filename, int flag, int mode)
143 fd = open (filename, flag, mode);
146 unexec_error ("Failure opening file %s", 1, (void *) filename, 0, 0);
151 unexec_mmap (int fd, size_t len, int prot, int flags)
157 return_val = mmap (0, len, prot, flags, fd, 0);
159 if (return_val == (caddr_t) -1)
160 unexec_error ("Failure mmap'ing file", 1, 0, 0, 0);
166 unexec_seek (int fd, long position)
171 unexec_error ("No file open in which to seek", 0, 0, 0, 0);
176 seek_value = (long) lseek (fd, 0, L_INCR);
178 seek_value = (long) lseek (fd, position, L_SET);
181 unexec_error ("Failed to do a seek to 0x%x in %s", 1,
182 (char *) position, "unexec() output file", 0);
188 unexec_read (int fd, long position, char *buf, int bytes)
192 position = unexec_seek (fd, position);
195 unexec_error ("Attempted read of %d bytes", 0, (char *) bytes, 0, 0);
201 n_read = read (fd, buf, remains);
203 unexec_error ("Read failed for 0x%x bytes at offset 0x%x in %s",
204 1, (char *) bytes, (char *) position,
205 "unexec() output file");
214 unexec_write (int fd, long position, char *buf, int bytes)
218 position = unexec_seek (fd, position);
221 unexec_error ("Attempted write of %d bytes in %s",
222 0, (char *) bytes, "unexec() output file", 0);
228 n_written = write (fd, buf, remains);
230 unexec_error ("Write failed for 0x%x bytes at offset 0x%x in %s",
231 1, (char *) bytes, (char *) position,
232 "unexec() output file");
234 remains -= n_written;
241 unexec_pad (int fd, int bytes)
246 int remaining = bytes;
248 memset (buf, 0, sizeof (buf));
250 while (remaining > 0)
252 int this_write = (remaining > sizeof(buf))?sizeof(buf):remaining;
253 unexec_write (fd, -1, buf, this_write);
254 remaining -= this_write;
260 unexec_fstat (int fd, struct stat *statptr)
263 if (-1 == fstat (fd, statptr))
264 unexec_error ("fstat() failed for descriptor %d", 1, (char *) fd, 0, 0);
269 unexec_fchmod (int fd, int mode)
272 if (-1 == fchmod (fd, mode))
273 unexec_error ("fchmod() failed for descriptor %d", 1, (char *) fd, 0, 0);
278 unexec_addr_to_offset (long addr, struct translation_struct *ts)
281 if ((addr < ts->txtaddr) || (addr >= ts->bssaddr))
282 unexec_error ("bad address 0x%x to addr_to_offset()",
283 0, (char *) addr, 0, 0);
284 if (addr >= ts->dataddr)
285 return ((long) ((addr - ts->dataddr) + ts->datoff));
287 return ((long) ((addr - ts->txtaddr) + ts->txtoff));
292 * "LD.SO" DATA AND SYMBOL TABLE OPERATIONS
296 copy_relocation_site (struct relocation_info *ri,
297 caddr_t from_base_addr,
298 caddr_t to_base_addr,
299 struct translation_struct *ts)
301 long offset = unexec_addr_to_offset (ri->r_address, ts);
302 caddr_t from = from_base_addr + offset;
303 caddr_t to = to_base_addr + offset;
306 #define r_type r_length
312 *((char *) to) = *((char *) from);
315 *((short *) to) = *((short *) from);
318 *((long *) to) = *((long *) from);
323 *((char *) to) = *((char *) from);
327 *((short *) to) = *((short *) from);
338 *((long *) to) = *((long *) from);
342 long *target = (long *) to;
343 long *source = (long *) from;
353 #endif /* !mc68020 */
355 unexec_error ("unknown reloc type %d seen during unexec()",
356 0, (char *) ri->r_type, 0, 0);
363 reset_symtab (struct nlist *start, struct nlist *end, char *strtab,
364 long edata_value, long end_value, int ld_so_table,
367 struct nlist *tmp = start;
373 int type = tmp->n_type;
374 int named = (ld_so_table)?1:(tmp->n_un.n_strx);
376 if ((type == (N_UNDF | N_EXT)) &&
378 unexec_error ("unexec'ing image has COMMON symbols in it -- we quit!",
381 if (!(type & N_STAB))
384 (type == (N_EXT | N_DATA)) &&
386 !strcmp ("_edata", strtab + tmp->n_un.n_strx))
388 tmp->n_value = edata_value;
393 if ((type & N_TYPE) == N_BSS)
396 (type == (N_EXT | N_BSS)) &&
398 !strcmp ("_end", strtab + tmp->n_un.n_strx))
400 tmp->n_value = end_value;
403 else if (type & N_EXT)
404 tmp->n_type = N_DATA | N_EXT;
406 tmp->n_type = N_DATA;
409 /* the way things are being handled here, having sbrk() in the
410 image is fatal for an image linked with shared lib's (although
411 the code could be modified to support it), but this should
412 never happen anyway */
414 (type == (N_EXT | N_TEXT)) &&
416 !strcmp ("_sbrk", strtab + tmp->n_un.n_strx))
417 unexec_error ("unexec'd shlib image has sbrk() in it -- we quit!",
425 extern int getpagesize (void);
431 /* this has to be a global variable to prevent the optimizers from
432 * assuming that it can not be 0.
434 static void *dynamic_addr = (void *) &_DYNAMIC;
437 unexec (char *new_name, char *old_name,
438 unsigned int emacs_edata, unsigned int dummy1, unsigned int dummy2)
441 struct link_dynamic *ld = 0;
442 struct link_dynamic_2 *ld2 = 0;
443 /* old and new state */
446 caddr_t old_base_addr;
447 caddr_t new_base_addr;
452 /* some process specific "constants" */
453 unsigned long n_pagsiz;
454 long page_size = getpagesize ();
456 caddr_t current_break = (caddr_t) sbrk (0);
459 unexec_error ("unexec() failed because we can't get the size of a page!",
462 /* see if this is a -Bdynamic image -- if so, find ld.so structures */
465 ld = (struct link_dynamic *) dynamic_addr;
466 ld2 = ld->ld_un.ld_2;
467 if (ld->ld_version < 2)
468 unexec_error ("%s linked with obsolete version of ld -- we quit!",
472 /* open the old and new files, figuring out how big the old one is
473 so that we can map it in */
474 old_fd = unexec_open (old_name, O_RDONLY, 0);
475 new_fd = unexec_open (new_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
477 /* setup the header and the statbuf for old_fd */
478 unexec_read (old_fd, 0, (char *) &old_hdr, sizeof (old_hdr));
479 unexec_fstat (old_fd, &old_buf);
482 /* set up some important constants */
483 n_pagsiz = N_PAGSIZ (old_hdr);
485 plt_end = (caddr_t) MASK_UP (ld2->ld_plt + ld2->ld_plt_sz, sizeof (double));
487 plt_end = (caddr_t) N_DATADDR (old_hdr);
489 /* never write protect the variable "environ", defined in /lib/crt0.o, and
490 set in process.c and callproc.c */
491 mprotect_bottom_addr = ((unsigned long) &environ) + sizeof (char **);
492 /* never protect ABOVE the end of data emacs_edata specified */
493 mprotect_top_addr = MIN (emacs_edata, N_DATADDR (old_hdr) + old_hdr.a_data);
495 /* Set up the image of the old file */
496 old_base_addr = unexec_mmap (old_fd, old_buf.st_size, PROT_READ, MAP_PRIVATE);
499 /* set up the new exec */
501 new_hdr.a_data = (((unsigned long) MASK_UP (current_break, n_pagsiz)) -
502 ((unsigned long) N_DATADDR (old_hdr)));
505 /* set up this variable, in case we want to reset "the break"
507 sbrk_of_0_at_unexec = ((unsigned long) MASK_UP (current_break, n_pagsiz));
509 /* Write out the first approximation to the new file. The sizes of
510 each section will be correct, but there will be a number of
511 corrections that will need to be made. */
513 long old_datoff = N_DATOFF (old_hdr);
514 long old_dataddr = N_DATADDR (old_hdr);
515 long new_treloff = N_TRELOFF (new_hdr);
516 long old_treloff = N_TRELOFF (old_hdr);
517 long ld_so_size = ((unsigned long) plt_end) - old_dataddr;
518 long real_data_size = current_break - plt_end;
520 MASK_UP (current_break, n_pagsiz) - ((unsigned long) current_break);
523 /* First, write the text segment with new header -- copy everything until
524 the start of the data segment from the old file, and then go back and
525 write the new header. */
526 unexec_write (new_fd, 0, old_base_addr, old_datoff + ld_so_size);
527 unexec_write (new_fd, 0, (char *) &new_hdr, sizeof (new_hdr));
529 /* Copy the rest of the data segment from the running image. */
530 unexec_write (new_fd, old_datoff + ld_so_size,
531 plt_end, real_data_size);
533 /* pad out the data segment */
534 unexec_pad (new_fd, pad_size);
536 /* Finally, copy the symbol table information from the old file. */
537 unexec_write (new_fd, new_treloff,
538 old_base_addr + old_treloff,
539 old_buf.st_size - old_treloff);
543 /* Next, map in the output file so that we can jump around fixing it
544 up. We retain the old file so that we can refer to it. */
545 unexec_fstat (new_fd, &new_buf);
546 new_base_addr = unexec_mmap (new_fd,
547 MASK_UP (new_buf.st_size, page_size),
548 PROT_READ | PROT_WRITE, MAP_SHARED);
552 /* We need to do 2 things. First, make sure that _edata and _end (and
553 hence, curbrk) are set to the correct values. At the same time, for
554 neatness and to help with debugging, mark all the types of all ld.so
555 and nm BSS symbols in the new file to be DATA, and make sure that
556 there are no COMMON symbols in the output file, as any references to
557 these can lose really big. Second, reset all of the ld.so "relocation
558 sites" in the new file to have the values that appear in the old file
559 -- the failure to do this was the biggest loser in the old version of
564 /* Reset the regular symbol table first. */
565 reset_symtab ((struct nlist *) (new_base_addr + N_SYMOFF(new_hdr)),
566 (struct nlist *) (new_base_addr + N_SYMOFF(new_hdr) +
568 (char *) (new_base_addr + N_STROFF(new_hdr)),
569 N_DATADDR (new_hdr) + new_hdr.a_data,
570 N_BSSADDR (new_hdr) + new_hdr.a_bss,
572 /* Now reset the ld.so symbol table. */
574 reset_symtab ((struct nlist *) (new_base_addr + ld2->ld_stab),
575 (struct nlist *) (new_base_addr + ld2->ld_symbols),
576 (char *) (new_base_addr + ld2->ld_symbols),
577 N_DATADDR (new_hdr) + new_hdr.a_data,
578 N_BSSADDR (new_hdr) + new_hdr.a_bss,
585 struct translation_struct ts;
586 struct relocation_info *tmp =
587 (struct relocation_info *) (old_base_addr + ld2->ld_rel);
588 struct relocation_info *end =
589 (struct relocation_info *)(old_base_addr + ld2->ld_hash);
591 /* set up the structure that we use to translate addresses in the
592 old file into file offsets */
593 ts.txtaddr = N_TXTADDR (old_hdr);
594 ts.txtoff = N_TXTOFF (old_hdr);
595 ts.dataddr = N_DATADDR (old_hdr);
596 ts.datoff = N_DATOFF (old_hdr);
597 ts.bssaddr = N_BSSADDR (old_hdr);
601 copy_relocation_site (tmp, old_base_addr, new_base_addr, &ts);
607 /* get rid of the mmap-ed file space and make the output file
608 executable -- then quit */
609 munmap (new_base_addr, MASK_UP (new_buf.st_size, page_size));
610 munmap (old_base_addr, MASK_UP (old_buf.st_size, page_size));
611 unexec_fchmod (new_fd, 0755);
618 run_time_remap (char *dummy)
620 long page_size = getpagesize();
621 unsigned long base_addr = MASK_UP (mprotect_bottom_addr, page_size);
622 unsigned long top_addr = MASK_DOWN (mprotect_top_addr, page_size);
623 long len = top_addr - base_addr;
627 unsigned long current_sbrk = (unsigned long) sbrk (0);
629 if (sbrk_of_0_at_unexec < current_sbrk)
631 if (sbrk_of_0_at_unexec != 0)
632 /* GCC -Wall even catches incorrect printf type errors.
635 "Absurd new brk addr = 0x%lx (current = 0x%lx)\n",
636 sbrk_of_0_at_unexec, current_sbrk);
641 if (brk ((caddr_t) sbrk_of_0_at_unexec))
642 fprintf (stderr, "failed to change brk addr to 0x%lx: %s\n",
643 sbrk_of_0_at_unexec, SYS_ERR);
650 if (mprotect ((caddr_t) base_addr, len, PROT_READ | PROT_EXEC))
651 fprintf (stderr, "failed to change protection on data pages: %s\n",