diff options
author | jdp <jdp@FreeBSD.org> | 1997-12-05 02:06:37 +0000 |
---|---|---|
committer | jdp <jdp@FreeBSD.org> | 1997-12-05 02:06:37 +0000 |
commit | 630123988385741ea95897b1d2533c27c6fee534 (patch) | |
tree | 4aa4f88263625ec858d790c959995c50e92d5368 | |
parent | a341ea06815e454bcf8a3ba2dbf5fd0a38d8c824 (diff) | |
download | FreeBSD-src-630123988385741ea95897b1d2533c27c6fee534.zip FreeBSD-src-630123988385741ea95897b1d2533c27c6fee534.tar.gz |
Make emacs work again. This is a workaround for the fact that the
emacs a.out file, self-generated by emacs's "unexec" function in
"unexsunos4.c", is invalid. In particular, its "_end" symbol has
the wrong value. The dynamic linker was using the value of that
symbol to initialize its sbrk break level.
The workaround is to peek at the executable's a.out header in
memory, and calculate what "_end" should be based on the segment
sizes.
I will work out a fix for emacs and send it to the FSF. This
dynamic linker workaround is still worthwhile, if only to avoid
forcing all emacs users to build a new version.
Note: xemacs gives a bogus warning at startup, for related reasons.
The warning is harmless and can safely be ignored. I will send a
patch to the xemacs maintainers to get rid of it, and meanwhile
add a patch file to our port.
-rw-r--r-- | gnu/usr.bin/ld/rtld/rtld.c | 51 | ||||
-rw-r--r-- | libexec/rtld-aout/rtld.c | 51 |
2 files changed, 66 insertions, 36 deletions
diff --git a/gnu/usr.bin/ld/rtld/rtld.c b/gnu/usr.bin/ld/rtld/rtld.c index efe912b..b331cde 100644 --- a/gnu/usr.bin/ld/rtld/rtld.c +++ b/gnu/usr.bin/ld/rtld/rtld.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: rtld.c,v 1.49 1997/09/18 13:55:45 phk Exp $ + * $Id: rtld.c,v 1.50 1997/11/29 03:32:47 jdp Exp $ */ #include <sys/param.h> @@ -234,7 +234,7 @@ static int reloc_map __P((struct so_map *, int)); static void reloc_copy __P((struct so_map *)); static void init_dag __P((struct so_map *)); static void init_sods __P((struct so_list *)); -static void init_internal_malloc __P((struct _dynamic *)); +static void init_internal_malloc __P((void)); static void init_external_malloc __P((void)); static int call_map __P((struct so_map *, char *)); static char *findhint __P((char *, int, int *)); @@ -347,7 +347,7 @@ struct _dynamic *dp; crtp->crt_dp->d_entry = &ld_entry; /* _DYNAMIC */ /* Initialize our internal malloc package. */ - init_internal_malloc(crtp->crt_dp); + init_internal_malloc(); /* Setup out (private) environ variable */ environ = crtp->crt_ep; @@ -2230,26 +2230,34 @@ static char *rtld_alloc_lev; * main program's sbrk arena. */ static void -init_internal_malloc(dp) - struct _dynamic *dp; +init_internal_malloc __P((void)) { - struct so_map tmp_map; - struct somap_private map_private; - struct nzlist *np; + const struct exec *hdr; /* * Before anything calls sbrk or brk, we have to initialize - * its idea of the current break level to the main program's - * "_end" symbol, rather than that of the dynamic linker. In - * order to do that, we need to look up the value of the main - * program's "_end" symbol. We set up a temporary link map - * entry for the main program so that we can do the lookup. + * its idea of the current break level to just beyond the main + * program's address space. Strictly speaking, the right + * way to do that is to look up the value of "_end" in the + * application's run time symbol table. + * + * That is what we used to do, and it works correctly for + * every valid program. Unfortunately, it doesn't work right + * for "unexec"ed versions of emacs. They are incorrectly + * generated with a wrong value for "_end". (xemacs gets it + * right.) + * + * To work around this, we peek at the exec header to get the + * sizes of the text, data, and bss segments. Luckily, the + * header is in memory at the start of the first mapped page. + * From the segment sizes, we can calculate a proper initial + * value for the break level. */ - init_link_map(&tmp_map, &map_private, NULL, NULL, NULL, NULL, dp); - np = lookup_in_obj(END_SYM, sym_hash(END_SYM), &tmp_map, 1); - if (np == NULL) - errx(1, "Main program has no symbol \"%s\"", END_SYM); - rtld_alloc_lev = curbrk = minbrk = (char *)np->nz_value; + hdr = (const struct exec *)PAGSIZ; + if (N_BADMAG(*hdr)) /* Sanity check */ + errx(1, "Cannot find program's a.out header"); + rtld_alloc_lev = curbrk = minbrk = + (char *)hdr + hdr->a_text + hdr->a_data + hdr->a_bss; } /* @@ -2267,6 +2275,13 @@ init_external_malloc __P((void)) *(char **)(sym_addr(CURBRK_SYM)) = curbrk; /* + * Set the minimum break level too. Otherwise, "unexec"ed + * emacs sets the break too low and wipes out our tables of + * shared objects. + */ + *(char **)(sym_addr(MINBRK_SYM)) = curbrk; + + /* * Set up pointers to the program's allocation functions, so * that we can use them from now on. */ diff --git a/libexec/rtld-aout/rtld.c b/libexec/rtld-aout/rtld.c index efe912b..b331cde 100644 --- a/libexec/rtld-aout/rtld.c +++ b/libexec/rtld-aout/rtld.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: rtld.c,v 1.49 1997/09/18 13:55:45 phk Exp $ + * $Id: rtld.c,v 1.50 1997/11/29 03:32:47 jdp Exp $ */ #include <sys/param.h> @@ -234,7 +234,7 @@ static int reloc_map __P((struct so_map *, int)); static void reloc_copy __P((struct so_map *)); static void init_dag __P((struct so_map *)); static void init_sods __P((struct so_list *)); -static void init_internal_malloc __P((struct _dynamic *)); +static void init_internal_malloc __P((void)); static void init_external_malloc __P((void)); static int call_map __P((struct so_map *, char *)); static char *findhint __P((char *, int, int *)); @@ -347,7 +347,7 @@ struct _dynamic *dp; crtp->crt_dp->d_entry = &ld_entry; /* _DYNAMIC */ /* Initialize our internal malloc package. */ - init_internal_malloc(crtp->crt_dp); + init_internal_malloc(); /* Setup out (private) environ variable */ environ = crtp->crt_ep; @@ -2230,26 +2230,34 @@ static char *rtld_alloc_lev; * main program's sbrk arena. */ static void -init_internal_malloc(dp) - struct _dynamic *dp; +init_internal_malloc __P((void)) { - struct so_map tmp_map; - struct somap_private map_private; - struct nzlist *np; + const struct exec *hdr; /* * Before anything calls sbrk or brk, we have to initialize - * its idea of the current break level to the main program's - * "_end" symbol, rather than that of the dynamic linker. In - * order to do that, we need to look up the value of the main - * program's "_end" symbol. We set up a temporary link map - * entry for the main program so that we can do the lookup. + * its idea of the current break level to just beyond the main + * program's address space. Strictly speaking, the right + * way to do that is to look up the value of "_end" in the + * application's run time symbol table. + * + * That is what we used to do, and it works correctly for + * every valid program. Unfortunately, it doesn't work right + * for "unexec"ed versions of emacs. They are incorrectly + * generated with a wrong value for "_end". (xemacs gets it + * right.) + * + * To work around this, we peek at the exec header to get the + * sizes of the text, data, and bss segments. Luckily, the + * header is in memory at the start of the first mapped page. + * From the segment sizes, we can calculate a proper initial + * value for the break level. */ - init_link_map(&tmp_map, &map_private, NULL, NULL, NULL, NULL, dp); - np = lookup_in_obj(END_SYM, sym_hash(END_SYM), &tmp_map, 1); - if (np == NULL) - errx(1, "Main program has no symbol \"%s\"", END_SYM); - rtld_alloc_lev = curbrk = minbrk = (char *)np->nz_value; + hdr = (const struct exec *)PAGSIZ; + if (N_BADMAG(*hdr)) /* Sanity check */ + errx(1, "Cannot find program's a.out header"); + rtld_alloc_lev = curbrk = minbrk = + (char *)hdr + hdr->a_text + hdr->a_data + hdr->a_bss; } /* @@ -2267,6 +2275,13 @@ init_external_malloc __P((void)) *(char **)(sym_addr(CURBRK_SYM)) = curbrk; /* + * Set the minimum break level too. Otherwise, "unexec"ed + * emacs sets the break too low and wipes out our tables of + * shared objects. + */ + *(char **)(sym_addr(MINBRK_SYM)) = curbrk; + + /* * Set up pointers to the program's allocation functions, so * that we can use them from now on. */ |