]>
code.delx.au - gnu-emacs/blob - src/unexsunos4.c
1 /* Unexec for Sunos 4 using shared libraries.
2 Copyright (C) 1990, 1994 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* Contributed by Viktor Dukhovni. */
22 * Unexec for Berkeley a.out format + SUNOS shared libraries
23 * The unexeced executable contains the __DYNAMIC area from the
24 * original text file, and then the rest of data + bss + malloced area of
25 * the current process. (The __DYNAMIC area is at the top of the process
26 * data segment, we use "data_start" defined externally to mark the start
27 * of the "real" data segment.)
29 * For programs that want to remap some of the data segment read only
30 * a run_time_remap is provided. This attempts to remap largest area starting
31 * and ending on page boundaries between "data_start" and "bndry"
32 * For this it to figure out where the text file is located. A path search
33 * is attempted after trying argv[0] and if all fails we simply do not remap
35 * One feature of run_time_remap () is mandatory: reseting the break.
37 * Note that we can no longer map data into the text segment, as this causes
38 * the __DYNAMIC struct to become read only, breaking the runtime loader.
39 * Thus we no longer need to mess with a private crt0.c, the standard one
40 * will do just fine, since environ can live in the writable area between
41 * __DYNAMIC and data_start, just make sure that pre-crt0.o (the name
42 * is somewhat abused here) is loaded first!
45 #include <sys/param.h>
53 /* Do this after the above #include's in case a configuration file wants
54 to define things for this file based on what <a.out.h> defines. */
59 #if defined (SUNOS4) || defined (__FreeBSD__)
60 #define UNDO_RELOCATION
63 #ifdef UNDO_RELOCATION
71 /* NetBSD needs this bit, but SunOS does not have it. */
78 * for programs other than emacs
79 * define data_start + initialized here, and make sure
80 * this object is loaded first!
81 * emacs will define these elsewhere, and load the object containing
82 * data_start (pre-crt0.o or firstfile.o?) first!
83 * The custom crt0.o *must not* be loaded!
86 static int data_start
= 0;
87 static int initialized
= 0;
89 extern int initialized
;
90 extern unsigned data_start
;
94 extern char *getenv ();
96 static struct exec nhdr
;
97 static int rd_only_len
;
101 unexec (new_name
, a_name
, bndry
, bss_start
, entry
)
102 char *new_name
, *a_name
;
103 unsigned bndry
, bss_start
, entry
;
107 struct exec ohdr
; /* Allocate on the stack, not needed in the next life */
111 fprintf (stderr
, "Used %d bytes of Pure Storage\n", pureptr
);
114 if ((fd
= open (a_name
, O_RDONLY
)) < 0)
116 fprintf (stderr
, "%s: open: ", a_name
);
120 if ((new = open (new_name
, O_WRONLY
| O_CREAT
, 0666)) == -1)
122 fprintf (stderr
, "%s: open: ", a_name
);
127 if ((fstat (fd
, &stat
) == -1))
129 fprintf (stderr
, "%s: ", a_name
);
134 old
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, fd
, 0);
135 if (old
== (char *)-1)
137 fprintf (stderr
, "%s: ", a_name
);
143 nhdr
= ohdr
= (*(struct exec
*)old
);
147 * Remember a magic cookie so we know we've got the right binary
152 Brk
= sbrk (0); /* Save the break, it is reset to &_end (by ld.so?) */
155 * Round up data start to a page boundary (Lose if not a 2 power!)
157 data_start
= ((((int)&data_start
) - 1) & ~(N_PAGSIZ (nhdr
) - 1)) + N_PAGSIZ (nhdr
);
160 * Round down read only pages to a multiple of the page size
163 rd_only_len
= ((int)bndry
& ~(N_PAGSIZ (nhdr
) - 1)) - data_start
;
166 /* Have to do this some time before dumping the data */
171 * Handle new data and bss sizes and optional new entry point.
172 * No one actually uses bss_start and entry, but tradition compels
173 * one to support them.
174 * Could complain if bss_start > Brk, but the caller is *supposed* to know
177 nhdr
.a_data
= (bss_start
? bss_start
: Brk
) - N_DATADDR (nhdr
);
178 nhdr
.a_bss
= bss_start
? Brk
- bss_start
: 0;
180 nhdr
.a_entry
= entry
;
183 * Write out the text segment with new header
184 * Dynamic executables are ZMAGIC with N_TXTOFF==0 and the header
185 * part of the text segment, but no need to rely on this.
186 * So write the TEXT first, then go back replace the header.
187 * Doing it in the other order is less general!
189 lseek (new, N_TXTOFF (nhdr
), L_SET
);
190 write (new, old
+ N_TXTOFF (ohdr
), N_TXTOFF (ohdr
) + ohdr
.a_text
);
191 lseek (new, 0L, L_SET
);
192 write (new, &nhdr
, sizeof (nhdr
));
195 * Write out the head of the old data segment from the file not
196 * from core, this has the unresolved __DYNAMIC relocation data
199 lseek (new, N_DATOFF (nhdr
), L_SET
);
200 write (new, old
+ N_DATOFF (ohdr
), (int)&data_start
- N_DATADDR (ohdr
));
203 * Copy the rest of the data from core
205 write (new, &data_start
, N_BSSADDR (nhdr
) - (int)&data_start
);
208 * Copy the symbol table and line numbers
210 lseek (new, N_TRELOFF (nhdr
), L_SET
);
211 write (new, old
+ N_TRELOFF (ohdr
), stat
.st_size
- N_TRELOFF (ohdr
));
213 /* Some other BSD systems use this file.
214 We don't know whether this change is right for them. */
215 #ifdef UNDO_RELOCATION
216 /* Undo the relocations done at startup by ld.so.
217 It will do these relocations again when we start the dumped Emacs.
218 Doing them twice gives incorrect results. */
220 unsigned long daddr
= N_DATADDR (ohdr
);
221 unsigned long rel
, erel
;
223 extern struct link_dynamic _DYNAMIC
;
225 /* SunOS4.x's ld_rel is relative to N_TXTADDR. */
226 if (_DYNAMIC
.ld_version
< 2)
228 rel
= _DYNAMIC
.ld_un
.ld_1
->ld_rel
+ N_TXTADDR (ohdr
);
229 erel
= _DYNAMIC
.ld_un
.ld_1
->ld_hash
+ N_TXTADDR (ohdr
);
233 rel
= _DYNAMIC
.ld_un
.ld_2
->ld_rel
+ N_TXTADDR (ohdr
);
234 erel
= _DYNAMIC
.ld_un
.ld_2
->ld_hash
+ N_TXTADDR (ohdr
);
237 #define REL_INFO_TYPE struct reloc_info_sparc
239 #define REL_INFO_TYPE struct reloc_info_m68k
241 #define REL_TARGET_ADDRESS(r) (((REL_INFO_TYPE *)(r))->r_address)
244 extern struct _dynamic _DYNAMIC
;
246 /* FreeBSD's LD_REL is a virtual address itself. */
247 rel
= LD_REL (&_DYNAMIC
);
248 erel
= rel
+ LD_RELSZ (&_DYNAMIC
);
249 #define REL_INFO_TYPE struct relocation_info
250 #define REL_TARGET_ADDRESS(r) (((REL_INFO_TYPE *)(r))->r_address)
253 for (; rel
< erel
; rel
+= sizeof (REL_INFO_TYPE
))
255 /* This is the virtual address where ld.so will do relocation. */
256 unsigned long target
= REL_TARGET_ADDRESS (rel
);
257 /* This is the offset in the data segment. */
258 unsigned long segoffset
= target
- daddr
;
260 /* If it is located below data_start, we have to do nothing here,
261 because the old data has been already written to the location. */
262 if (target
< (unsigned long)&data_start
)
265 lseek (new, N_DATOFF (nhdr
) + segoffset
, L_SET
);
266 write (new, old
+ N_DATOFF (ohdr
) + segoffset
, sizeof (unsigned long));
269 #endif /* UNDO_RELOCATION */
275 run_time_remap (progname
)
278 char aout
[MAXPATHLEN
];
279 register char *path
, *p
;
285 /* Restore the break */
288 /* If nothing to remap: we are done! */
289 if (rd_only_len
== 0)
293 * Attempt to find the executable
294 * First try argv[0], will almost always succeed as shells tend to give
295 * the full path from the hash list rather than using execvp ()
297 if (is_it (progname
))
301 * If argv[0] is a full path and does not exist, not much sense in
304 if (strchr (progname
, '/'))
308 * Try to search for argv[0] on the PATH
310 path
= getenv ("PATH");
316 /* copy through ':' or end */
317 for (p
= aout
; *p
= *path
; ++p
, ++path
)
320 ++path
; /* move past ':' */
324 strcpy (p
, progname
);
326 * aout is a candidate full path name
337 long filenames_cookie
;
341 * Open an executable and check for a valid header!
342 * Can't bcmp the header with what we had, it may have been stripped!
343 * so we may save looking at non executables with the same name, mostly
346 fd
= open (filename
, O_RDONLY
);
349 if (read (fd
, &hdr
, sizeof (hdr
)) == sizeof (hdr
)
350 && !N_BADMAG (hdr
) && N_DATOFF (hdr
) == N_DATOFF (nhdr
)
351 && N_TRELOFF (hdr
) == N_TRELOFF (nhdr
))
353 /* compare cookies */
354 lseek (fd
, N_DATOFF (hdr
) + (int)&cookie
- N_DATADDR (hdr
), L_SET
);
355 read (fd
, &filenames_cookie
, sizeof (filenames_cookie
));
356 if (filenames_cookie
== cookie
)
361 * The PROT_EXEC may not be needed, but it is safer this way.
362 * should the shared library decide to indirect through
363 * addresses in the data segment not part of __DYNAMIC
365 mmap (data_start
, rd_only_len
, PROT_READ
| PROT_EXEC
,
366 MAP_FILE
| MAP_SHARED
| MAP_FIXED
, fd
,
367 N_DATOFF (hdr
) + data_start
- N_DATADDR (hdr
));