1 /* Contributed by Viktor Dukhovni. */
3 * Unexec for Berkeley a.out format + SUNOS shared libraries
4 * The unexeced executable contains the __DYNAMIC area from the
5 * original text file, and then the rest of data + bss + malloced area of
6 * the current process. (The __DYNAMIC area is at the top of the process
7 * data segment, we use "data_start" defined externally to mark the start
8 * of the "real" data segment.)
10 * For programs that want to remap some of the data segment read only
11 * a run_time_remap is provided. This attempts to remap largest area starting
12 * and ending on page boundaries between "data_start" and "bndry"
13 * For this it to figure out where the text file is located. A path search
14 * is attempted after trying argv[0] and if all fails we simply do not remap
16 * One feature of run_time_remap () is mandatory: reseting the break.
18 * Note that we can no longer map data into the text segment, as this causes
19 * the __DYNAMIC struct to become read only, breaking the runtime loader.
20 * Thus we no longer need to mess with a private crt0.c, the standard one
21 * will do just fine, since environ can live in the writable area between
22 * __DYNAMIC and data_start, just make sure that pre-crt0.o (the name
23 * is somewhat abused here) is loaded first!
25 * $Log: unexsunos4.c,v $
26 * Revision 1.3 90/02/15 04:27:40 root
27 * Now it actually works.
29 * Revision 1.2 90/02/15 02:02:01 root
30 * Many comments, fixes, works not only with emacs.
32 * Revision 1.1 90/01/29 19:43:46 root
40 #include <sys/param.h>
49 * for programs other than emacs
50 * define data_start + initialized here, and make sure
51 * this object is loaded first!
52 * emacs will define these elsewhere, and load the object containing
53 * data_start (pre-crt0.o or firstfile.o?) first!
54 * The custom crt0.o *must not* be loaded!
57 static int data_start
= 0;
58 static int initialized
= 0;
60 extern int initialized
;
61 extern unsigned data_start
;
65 extern char *getenv ();
67 static struct exec nhdr
;
68 static int rd_only_len
;
72 unexec (new_name
, a_name
, bndry
, bss_start
, entry
)
73 char *new_name
, *a_name
;
74 unsigned bndry
, bss_start
, entry
;
79 struct exec ohdr
; /* Allocate on the stack, not needed in the next life */
83 fprintf (stderr
, "Used %d bytes of Pure Storage\n", pureptr
);
86 if ((fd
= open (a_name
, O_RDONLY
)) < 0)
88 fprintf (stderr
, "%s: open: ", a_name
);
92 if ((new = open (new_name
, O_WRONLY
| O_CREAT
, 0666)) == -1)
94 fprintf (stderr
, "%s: open: ", a_name
);
99 if ((fstat (fd
, &stat
) == -1))
101 fprintf (stderr
, "%s: ", a_name
);
106 old
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
107 if (old
== (char *)-1)
109 fprintf (stderr
, "%s: ", a_name
);
115 nhdr
= ohdr
= (*(struct exec
*)old
);
119 * Remeber a magic cookie so we know we've got the right binary
124 Brk
= sbrk (0); /* Save the break, it is reset to &_end (by ld.so?) */
127 * Round up data start to a page boundary (Lose if not a 2 power!)
129 data_start
= ((((int)&data_start
) - 1) & ~(N_PAGSIZ (nhdr
) - 1)) + N_PAGSIZ (nhdr
);
132 * Round down read only pages to a multiple of the page size
135 rd_only_len
= ((int)bndry
& ~(N_PAGSIZ (nhdr
) - 1)) - data_start
;
138 /* Have to do this some time before dumping the data */
143 * Handle new data and bss sizes and optional new entry point.
144 * No one actually uses bss_start and entry, but tradition compels
145 * one to support them.
146 * Could complain if bss_start > Brk, but the caller is *supposed* to know
149 nhdr
.a_data
= (bss_start
? bss_start
: Brk
) - N_DATADDR (nhdr
);
150 nhdr
.a_bss
= bss_start
? Brk
- bss_start
: 0;
152 nhdr
.a_entry
= entry
;
155 * Write out the text segment with new header
156 * Dynamic executables are ZMAGIC with N_TXTOFF==0 and the header
157 * part of the text segment, but no need to rely on this.
158 * So write the TEXT first, then go back replace the header.
159 * Doing it in the other order is less general!
161 lseek (new, N_TXTOFF (nhdr
), L_SET
);
162 write (new, old
+ N_TXTOFF (ohdr
), N_TXTOFF (ohdr
) + ohdr
.a_text
);
163 lseek (new, 0L, L_SET
);
164 write (new, &nhdr
, sizeof (nhdr
));
167 * Write out the head of the old data segment from the file not
168 * from core, this has the unresolved __DYNAMIC relocation data
171 lseek (new, N_DATOFF (nhdr
), L_SET
);
172 write (new, old
+ N_DATOFF (ohdr
), (int)&data_start
- N_DATADDR (ohdr
));
175 * Copy the rest of the data from core
177 write (new, &data_start
, N_BSSADDR (nhdr
) - (int)&data_start
);
180 * Copy the symbol table and line numbers
182 lseek (new, N_TRELOFF (nhdr
), L_SET
);
183 write (new, old
+ N_TRELOFF (ohdr
), stat
.st_size
- N_TRELOFF (ohdr
));
189 run_time_remap (progname
)
192 char aout
[MAXPATHLEN
];
193 register char *path
, *p
;
199 /* Restore the break */
202 /* If nothing to remap: we are done! */
203 if (rd_only_len
== 0)
207 * Attempt to find the executable
208 * First try argv[0], will almost always succeed as shells tend to give
209 * the full path from the hash list rather than using execvp ()
211 if (is_it (progname
))
215 * If argv[0] is a full path and does not exist, not much sense in
218 if (strchr (progname
, '/'))
222 * Try to search for argv[0] on the PATH
224 path
= getenv ("PATH");
230 /* copy through ':' or end */
231 for (p
= aout
; *p
= *path
; ++p
, ++path
)
234 ++path
; /* move past ':' */
238 strcpy (p
, progname
);
240 * aout is a candidate full path name
255 * Open an executable and check for a valid header!
256 * Can't bcmp() the header with what we had, it may have been stripped!
257 * so we may save looking at non executables with the same name, mostly
260 fd
= open (path
, O_RDONLY
);
263 if (read (fd
, &hdr
, sizeof (hdr
)) == sizeof (hdr
)
264 && !N_BADMAG (hdr
) && N_DATOFF (hdr
) == N_DATOFF (nhdr
)
265 && N_TRELOFF (hdr
) == N_TRELOFF (nhdr
))
267 /* compare cookies */
268 lseek (fd
, N_DATOFF (hdr
) + (int)&cookie
- N_DATADDR (hdr
), L_SET
);
269 read (fd
, &paths_cookie
, sizeof (paths_cookie
));
270 if (paths_cookie
== cookie
)
275 * The PROT_EXEC may not be needed, but it is safer this way.
276 * should the shared library decide to indirect through
277 * addresses in the data segment not part of __DYNAMIC
279 mmap (data_start
, rd_only_len
, PROT_READ
| PROT_EXEC
,
280 MAP_SHARED
| MAP_FIXED
, fd
,
281 N_DATOFF (hdr
) + data_start
- N_DATADDR (hdr
));