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!
30 #include <sys/param.h>
39 * for programs other than emacs
40 * define data_start + initialized here, and make sure
41 * this object is loaded first!
42 * emacs will define these elsewhere, and load the object containing
43 * data_start (pre-crt0.o or firstfile.o?) first!
44 * The custom crt0.o *must not* be loaded!
47 static int data_start
= 0;
48 static int initialized
= 0;
50 extern int initialized
;
51 extern unsigned data_start
;
55 extern char *getenv ();
57 static struct exec nhdr
;
58 static int rd_only_len
;
62 unexec (new_name
, a_name
, bndry
, bss_start
, entry
)
63 char *new_name
, *a_name
;
64 unsigned bndry
, bss_start
, entry
;
69 struct exec ohdr
; /* Allocate on the stack, not needed in the next life */
73 fprintf (stderr
, "Used %d bytes of Pure Storage\n", pureptr
);
76 if ((fd
= open (a_name
, O_RDONLY
)) < 0)
78 fprintf (stderr
, "%s: open: ", a_name
);
82 if ((new = open (new_name
, O_WRONLY
| O_CREAT
, 0666)) == -1)
84 fprintf (stderr
, "%s: open: ", a_name
);
89 if ((fstat (fd
, &stat
) == -1))
91 fprintf (stderr
, "%s: ", a_name
);
96 old
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
97 if (old
== (char *)-1)
99 fprintf (stderr
, "%s: ", a_name
);
105 nhdr
= ohdr
= (*(struct exec
*)old
);
109 * Remeber a magic cookie so we know we've got the right binary
114 Brk
= sbrk (0); /* Save the break, it is reset to &_end (by ld.so?) */
117 * Round up data start to a page boundary (Lose if not a 2 power!)
119 data_start
= ((((int)&data_start
) - 1) & ~(N_PAGSIZ (nhdr
) - 1)) + N_PAGSIZ (nhdr
);
122 * Round down read only pages to a multiple of the page size
125 rd_only_len
= ((int)bndry
& ~(N_PAGSIZ (nhdr
) - 1)) - data_start
;
128 /* Have to do this some time before dumping the data */
133 * Handle new data and bss sizes and optional new entry point.
134 * No one actually uses bss_start and entry, but tradition compels
135 * one to support them.
136 * Could complain if bss_start > Brk, but the caller is *supposed* to know
139 nhdr
.a_data
= (bss_start
? bss_start
: Brk
) - N_DATADDR (nhdr
);
140 nhdr
.a_bss
= bss_start
? Brk
- bss_start
: 0;
142 nhdr
.a_entry
= entry
;
145 * Write out the text segment with new header
146 * Dynamic executables are ZMAGIC with N_TXTOFF==0 and the header
147 * part of the text segment, but no need to rely on this.
148 * So write the TEXT first, then go back replace the header.
149 * Doing it in the other order is less general!
151 lseek (new, N_TXTOFF (nhdr
), L_SET
);
152 write (new, old
+ N_TXTOFF (ohdr
), N_TXTOFF (ohdr
) + ohdr
.a_text
);
153 lseek (new, 0L, L_SET
);
154 write (new, &nhdr
, sizeof (nhdr
));
157 * Write out the head of the old data segment from the file not
158 * from core, this has the unresolved __DYNAMIC relocation data
161 lseek (new, N_DATOFF (nhdr
), L_SET
);
162 write (new, old
+ N_DATOFF (ohdr
), (int)&data_start
- N_DATADDR (ohdr
));
165 * Copy the rest of the data from core
167 write (new, &data_start
, N_BSSADDR (nhdr
) - (int)&data_start
);
170 * Copy the symbol table and line numbers
172 lseek (new, N_TRELOFF (nhdr
), L_SET
);
173 write (new, old
+ N_TRELOFF (ohdr
), stat
.st_size
- N_TRELOFF (ohdr
));
179 run_time_remap (progname
)
182 char aout
[MAXPATHLEN
];
183 register char *path
, *p
;
189 /* Restore the break */
192 /* If nothing to remap: we are done! */
193 if (rd_only_len
== 0)
197 * Attempt to find the executable
198 * First try argv[0], will almost always succeed as shells tend to give
199 * the full path from the hash list rather than using execvp ()
201 if (is_it (progname
))
205 * If argv[0] is a full path and does not exist, not much sense in
208 if (strchr (progname
, '/'))
212 * Try to search for argv[0] on the PATH
214 path
= getenv ("PATH");
220 /* copy through ':' or end */
221 for (p
= aout
; *p
= *path
; ++p
, ++path
)
224 ++path
; /* move past ':' */
228 strcpy (p
, progname
);
230 * aout is a candidate full path name
245 * Open an executable and check for a valid header!
246 * Can't bcmp() the header with what we had, it may have been stripped!
247 * so we may save looking at non executables with the same name, mostly
250 fd
= open (path
, O_RDONLY
);
253 if (read (fd
, &hdr
, sizeof (hdr
)) == sizeof (hdr
)
254 && !N_BADMAG (hdr
) && N_DATOFF (hdr
) == N_DATOFF (nhdr
)
255 && N_TRELOFF (hdr
) == N_TRELOFF (nhdr
))
257 /* compare cookies */
258 lseek (fd
, N_DATOFF (hdr
) + (int)&cookie
- N_DATADDR (hdr
), L_SET
);
259 read (fd
, &paths_cookie
, sizeof (paths_cookie
));
260 if (paths_cookie
== cookie
)
265 * The PROT_EXEC may not be needed, but it is safer this way.
266 * should the shared library decide to indirect through
267 * addresses in the data segment not part of __DYNAMIC
269 mmap (data_start
, rd_only_len
, PROT_READ
| PROT_EXEC
,
270 MAP_SHARED
| MAP_FIXED
, fd
,
271 N_DATOFF (hdr
) + data_start
- N_DATADDR (hdr
));