[gnu.emacs.bug] Shared libraries versus dumping

jeffrey@algor2.UUCP (Jeffrey Kegler) (07/06/89)

On my system (80386 running Bell Tech or Intel S5R3.2u) emacs will not dump
successfully when compiled using one of the shared libraries.  Alas, I only have
X11 in shared library form.  Is there a way to get dumping and shared libraries
to coexist?
-- 

Jeffrey Kegler, President, Algorists,
jeffrey@algor2.UU.NET or uunet!algor2!jeffrey
1762 Wainwright DR, Reston VA 22090

james@bigtex.cactus.org (James Van Artsdalen) (07/09/89)

In <467@algor2.UUCP>, jeffrey@algor2.UUCP (Jeffrey Kegler) wrote:

> On my system (80386 running Bell Tech or Intel S5R3.2u) emacs will not
> dump successfully when compiled using one of the shared libraries.

The immediate problem is likely that the emacs unexec() function is
not emitting the right COFF sections.  In addition to .text, .data and
.bss, a binary linked with shared libraries also has .lib, .fka?00 and
.fka?40 sections (the ? depends on which shared library is referenced:
each shared library referenced has its own .fka?00 and .fka?40 in the
COFF file).  I believe that the .lib section contains the paths to the
shared libraries themselves, and suspect that the .fka* sections map
the code & data of the shared library into the process address space.

> Alas, I only have X11 in shared library form.  Is there a way to get
> dumping and shared libraries to coexist?

I've managed to generate an xemacs that uses shared libraries that the
kernel will exec(2).  It took a number of kludgy hard-coded hacks to
unexec.c, as the standard unexec doesn't copy over sections it doesn't
understand (ie, .lib and .fka*).  This xemacs actually runs in emacs.c
for a while.

Unfortunately, the next problem is much harder, and probably prevents
any good solution.  In COFF .o files there can be a section called
".init".  When linking, all .init sections appear to be simply
concatinated together and placed at the front of the emitted .text
section.  This allows library routines to get control for
initialization and program startup.  No .init section actually appears
in the executable, as the code really is in the .text section.

I suspect .init would be most useful for g++.

The killer is that malloc() appears to use the .init section to
initialize a variable called _libc_end (kept in the high address space
used for the libc_s shared library, not in .data or .bss) that is
apparently a pointer to the base of the .bss section.  In addition,
other variables whose function I haven't figured out are initialized
too (this is all derived from disassembly and "nm /lib/libc_s.a").

Here's the section header dump from a temacs compiled with libc_s:

			***SECTION HEADER***
	Name        Paddr       Vaddr       Scnptr      Relptr     Lnnoptr
	            Flags                    Size       Nreloc      Nlnno

temacs:
	.text     0x00000148  0x00000148  0x00000148  0x00000000  0x00072604
	          0x00000020              0x00049d64        0         193

	.data     0x00400eac  0x00400eac  0x00049eac  0x00000000  0x00000000
	          0x00000040              0x0002423c        0           0

	.bss      0x004250e8  0x004250e8  0x00000000  0x00000000  0x00000000
	          0x00000080              0x00006320        0           0

	.fka000   0xa0000000  0xa0000000  0x00000000  0x00000000  0x00000000
	          0x00000022              0x00004b98        0           0

	.fka040   0xa0400000  0xa0400000  0x00000000  0x00000000  0x00000000
	          0x00000042              0x00000628        0           0

	.comment  0x00000000  0x00000000  0x0006e0e8  0x00000000  0x00000000
	          0x00000200              0x00004504        0           0

	.lib      0x00000001  0x00000000  0x000725ec  0x00000000  0x00000000
	          0x00000800              0x00000018        0           0

My modified unexec() copies over the .fka0?0 section headers and the
.lib header and data (.fka* have no section data).  Here's what a
disassembly of the first few instructions executed in temacs looks
like:

disassembly for temacs

section	.text
_istart()
	 148:  c7 05 04 00 40 a0 00 4a 42 00 movl   $0x424a00,0xa0400004
	 152:  90                     nop    
	 153:  90                     nop    
	 154:  c7 05 18 00 40 a0 18 ae 42 00 movl   $0x42ae18,0xa0400018
	 15e:  c7 05 1c 00 40 a0 8c 8f 42 00 movl   $0x428f8c,0xa040001c
	 168:  c7 05 20 00 40 a0 20 b2 42 00 movl   $0x42b220,0xa0400020
	 172:  c7 05 24 00 40 a0 28 4c 42 00 movl   $0x424c28,0xa0400024
	 17c:  c7 05 28 00 40 a0 e8 4f 42 00 movl   $0x424fe8,0xa0400028
	 186:  c7 05 2c 00 40 a0 ec 4f 42 00 movl   $0x424fec,0xa040002c
	 190:  c7 05 34 00 40 a0 0f 00 00 a0 movl   $0xa000000f,0xa0400034
	 19a:  c7 05 30 00 40 a0 08 b4 42 00 movl   $0x42b408,0xa0400030
	 1a4:  c7 05 38 00 40 a0 b0 0e 40 00 movl   $0x400eb0,0xa0400038
	 1ae:  90                     nop    
	 1af:  90                     nop    
	 1b0:  c7 05 08 00 40 a0 94 3b 04 00 movl   $0x43b94,0xa0400008
	 1ba:  90                     nop    
	 1bb:  90                     nop    
	 1bc:  c7 05 10 00 40 a0 24 3c 04 00 movl   $0x43c24,0xa0400010
	 1c6:  c7 05 14 00 40 a0 e0 50 42 00 movl   $0x4250e0,0xa0400014
	 1d0:  c3                     ret    
	 1d1:  90                     nop    
	 1d2:  90                     nop    
	 1d3:  90                     nop    
gcc_compiled.()
_start()
	 1d4:  83 ec 08               subl   $0x8,%esp

_start() is the traditional /lib/crt0.o start, and istart() is
conjured up by the linker for the .init stuff: everything between
_istart() and _start() came from .init sections of various routines in
the C library (_start() is the true entry point, and it calls istart()
though I don't show that call here).  The movl at address 19a is the
likely culprit: it appears to want to point to the first byte after
.bss.  After undumping, this constant is no longer valid because the
data space as a whole grew.

I tried to add the statement

extern int _libc_end; _libc_end = sbrk(0);

to main() in emacs.c, but it turns out that sbrk(2) isn't really a
kernel call: it just adds a remembered constant to the argument and
calls brk(2).  The remembered constant appears derived from _libc_end,
so since there appears to be no other way of telling where the end of
.bss is, unexec() will probably have to search the start of the text
region for the movl and patch the correct constant...  :-(

If anyone has any questions/comments/suggestions, please let me
know.
-- 
James R. Van Artsdalen          james@bigtex.cactus.org   "Live Free or Die"
Dell Computer Co    9505 Arboretum Blvd Austin TX 78759         512-338-8789

james@bigtex.cactus.org (James Van Artsdalen) (07/10/89)

In <18854@bigtex.cactus.org>, james@bigtex.cactus.org (That's Me) wrote:

> This xemacs actually runs in emacs.c for a while.

> Unfortunately, the next problem is much harder, and probably prevents
> any good solution.

It may not be good, but here are patches to allow one to unexec with
shared libraries and run for more than "a while".  The changes are as
hacky as unexec.c ever was, so no guaranteeing that it works: I don't
recommend trying it unless you're willing to use gdb and fix it.  I
have tested the result with and without shared libraries, and with gcc
and pcc.  I am using s-usg5-3.h and m-intel386.h.

Add this mess to the end of your config.h file.  USG_SHARED_LIBRARIES
is what flags the use of shared libraries.  Only -lc_s goes here now,
because various other places know about -lX11_s and -lnsl_s.  The
alloca() and GNULIB are for compiling emacs with GNU C.  The stuff at
the very end is for changing the libraries and start files that
xmakefile will want to use.

#define USG_SHARED_LIBRARIES -lc_s

#if defined(__GNUC__) && !defined(alloca)
#define alloca(n) __builtin_alloca(n)
#endif

#ifdef __GNUC__
#define GNULIB /nfs/raid/lib/gcc-gnulib
#else
#define GNULIB
#endif

#undef LIB_STANDARD
#ifdef USG_SHARED_LIBRARIES
#ifdef X11
#define LIB_X11_LIB -lX11_s
#endif /* X11 */
#define START_FILES pre-crt0.o /lib/crt1.o
#define LIB_STANDARD -linet USG_SHARED_LIBRARIES GNULIB -lPW -lg -lc \
		     /lib/crtn.o
#else /* USG_SHARED_LIBRARIES */
#define LIB_STANDARD -linet -lPW -lg -lc GNULIB
#endif /* USG_SHARED_LIBRARIES */

-------------------------------------------------------------------------------
Here are the patches.  The change to emacs.c is to handle the sbrk(0)
problem: without it sbrk(0) returns the wrong thing and confuses
malloc(3c).  The changes to ymakefile is so that the X library can
have a name other than libX11.a (which it will if shared).  The
makefile #define is so that my config.h will not define certain inline
asm functions not shown here.  In unexec.c, "bias" is calculated
differently - I couldn't make the old definition work.  The basic
algorithm is to scan the section headers in the original file once
find the text, data and bss headers (and to find the end of section
data), again to write all section headers in the right order, and
again to write the section data in the right order.  Any unrecognized
sections will be simply written out as is.  I probably shouldn't have
renamed copy_text_and_data, but I thought the result would be
different than it turned out to be.  The biggest non-obvious
limitation is that I don't believe that the unexec() changes will work
if the text section isn't first, or if anything comes between text,
data & bss.

*** /tmp/,RCSt1a01031	Sun Jul  9 21:36:34 1989
--- emacs.c	Sun Jul  9 20:43:33 1989
***************
*** 81,86 ****
--- 81,88 ----
  int xargc;
  #endif /* HAVE_X_WINDOWS */
  
+ unsigned int bss_end = 0;
+ 
  /* Nonzero means running Emacs without interactive terminal.  */
  
  int noninteractive;
***************
*** 202,207 ****
--- 204,214 ----
  #endif /* SHAREABLE_LIB_BUG */
  #endif /* LINK_CRTL_SHARE */
  #endif /* VMS */
+ 
+ #ifdef USG_SHARED_LIBRARIES
+   if (bss_end)
+     brk(bss_end);
+ #endif
  
    clearerr (stdin);
  
*** /tmp/,RCSt1a01031	Sun Jul  9 21:36:36 1989
--- ymakefile	Sun Jul  9 20:46:19 1989
***************
*** 27,32 ****
--- 27,33 ----
  cppdir = ../cpp/
  
  #define NO_SHORTNAMES
+ #define MAKEFILE
  #include "config.h"
  
  /* Use HAVE_X11 as an alias for X11 in this file
***************
*** 38,43 ****
--- 39,48 ----
  #undef X11
  #endif
  
+ #ifndef LIB_X11_LIB
+ #define LIB_X11_LIB -lX11
+ #endif
+ 
  /* On some machines #define register is done in config;
     don't let it interfere with this file.  */
  #undef register
***************
*** 173,182 ****
  #ifdef HAVE_X11
  #ifdef HAVE_X_MENU
  XOBJ = x11term.o x11fns.o xmenu.o
! LIBX = -lXMenu -loldX -lX11 LIBX11_MACHINE LIBX11_SYSTEM
  #else
  XOBJ = x11term.o x11fns.o
! LIBX = -lX11 LIBX11_MACHINE LIBX11_SYSTEM
  #endif
  #else /* not HAVE_X11 */
  #ifdef HAVE_X_MENU
--- 178,187 ----
  #ifdef HAVE_X11
  #ifdef HAVE_X_MENU
  XOBJ = x11term.o x11fns.o xmenu.o
! LIBX = -lXMenu -loldX LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM
  #else
  XOBJ = x11term.o x11fns.o
! LIBX = LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM
  #endif
  #else /* not HAVE_X11 */
  #ifdef HAVE_X_MENU
*** /tmp/,RCSt1a01031	Sun Jul  9 21:36:37 1989
--- unexec.c	Sun Jul  9 21:35:51 1989
***************
*** 400,406 ****
      }
  
    if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
!       || copy_text_and_data (new) < 0
        || copy_sym (new, a_out, a_name, new_name) < 0
  #ifdef COFF
        || adjust_lnnoptrs (new, a_out, new_name) < 0
--- 400,406 ----
      }
  
    if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
!       || copy_sections (new, a_out) < 0
        || copy_sym (new, a_out, a_name, new_name) < 0
  #ifdef COFF
        || adjust_lnnoptrs (new, a_out, new_name) < 0
***************
*** 440,446 ****
    auto struct scnhdr scntemp;		/* Temporary section header */
    register int scns;
  #endif /* COFF */
!   unsigned int bss_end;
  
    pagemask = getpagesize () - 1;
  
--- 440,446 ----
    auto struct scnhdr scntemp;		/* Temporary section header */
    register int scns;
  #endif /* COFF */
!   extern unsigned int bss_end;
  
    pagemask = getpagesize () - 1;
  
***************
*** 533,538 ****
--- 533,541 ----
    /* Now we alter the contents of all the f_*hdr variables
       to correspond to what we want to dump.  */
  
+   bias = (bss_start - f_ohdr.data_start) + (bss_end - bss_start) -
+     f_dhdr.s_size;
+ 
    f_hdr.f_flags |= (F_RELFLG | F_EXEC);
  #ifdef EXEC_MAGIC
    f_ohdr.magic = EXEC_MAGIC;
***************
*** 576,582 ****
    f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
    f_bhdr.s_size = f_ohdr.bsize;
    f_bhdr.s_scnptr = 0L;
-   bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start;
  
    if (f_hdr.f_symptr > 0L)
      {
--- 579,584 ----
***************
*** 602,621 ****
        PERROR (new_name);
      }
  
!   if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
!     {
!       PERROR (new_name);
!     }
  
!   if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
!     {
!       PERROR (new_name);
!     }
  
-   if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
-     {
-       PERROR (new_name);
-     }
    return (0);
  
  #else /* if not COFF */
--- 604,632 ----
        PERROR (new_name);
      }
  
!   lseek(a_out, sizeof f_hdr + sizeof f_ohdr, 0);
  
!   for (scns = f_hdr.f_nscns; scns > 0; scns--) {
!      if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
!        PERROR (a_name);
! 
!      if (!strcmp(scntemp.s_name, f_thdr.s_name)) {
! 	if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
! 	  PERROR (new_name);
!      } else if (!strcmp(scntemp.s_name, f_dhdr.s_name)) {
! 	if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
! 	   PERROR (new_name);
!      } else if (!strcmp(scntemp.s_name, f_bhdr.s_name)) {
! 	if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
! 	   PERROR (new_name);
!      } else {
! 	if (scntemp.s_scnptr)
! 	  scntemp.s_scnptr += bias;
! 	if (write (new, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
! 	  PERROR (new_name);
!      }
!   }
  
    return (0);
  
  #else /* if not COFF */
***************
*** 680,706 ****
  }
  
  /* ****************************************************************
!  * copy_text_and_data
   *
!  * Copy the text and data segments from memory to the new a.out
   */
  static int
! copy_text_and_data (new)
!      int new;
  {
    register char *end;
    register char *ptr;
  
  #ifdef COFF
!   lseek (new, (long) text_scnptr, 0);
!   ptr = (char *) f_ohdr.text_start;
!   end = ptr + f_ohdr.tsize;
!   write_segment (new, ptr, end);
  
!   lseek (new, (long) data_scnptr, 0);
!   ptr = (char *) f_ohdr.data_start;
!   end = ptr + f_ohdr.dsize;
!   write_segment (new, ptr, end);
  
  #else /* if not COFF */
  
--- 691,743 ----
  }
  
  /* ****************************************************************
!  * copy_sections
   *
!  * Copy all sections to the new a.out
   */
  static int
! copy_sections (new, a_out)
!      int new, a_out;
  {
    register char *end;
    register char *ptr;
+   register int scns;
+   auto struct scnhdr scntemp;		/* Temporary section header */
  
  #ifdef COFF
! 
!   lseek(a_out, sizeof(struct filehdr) + sizeof(struct aouthdr), 0);
  
!   for (scns = f_hdr.f_nscns; scns > 0; scns--) {
!      if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
!        PERROR ("temacs");
! 
!      if (!strcmp(scntemp.s_name, ".text")) {
! 	lseek (new, (long) text_scnptr, 0);
! 	ptr = (char *) f_ohdr.text_start;
! 	end = ptr + f_ohdr.tsize;
! 	write_segment (new, ptr, end);
!      } else if (!strcmp(scntemp.s_name, ".data")) {
! 	lseek (new, (long) data_scnptr, 0);
! 	ptr = (char *) f_ohdr.data_start;
! 	end = ptr + f_ohdr.dsize;
! 	write_segment (new, ptr, end);
!      } else if (!scntemp.s_scnptr)
!        ; /* do nothing - no data for this section */
!      else {
! 	char page[BUFSIZ];
! 	int size, n;
! 	int old_a_out_ptr = lseek(a_out, 0, 1);
! 
! 	lseek(a_out, scntemp.s_scnptr, 0);
! 	for (size = scntemp.s_size; size > 0; size -= sizeof page) {
! 	   n = size > sizeof page ? sizeof page : size;
! 	   if (read(a_out, page, n) != n || write(new, page, n) != n)
! 	     PERROR ("xemacs");
! 	}
! 	lseek(a_out, old_a_out_ptr, 0);
!      }
!   }
  
  #else /* if not COFF */
  


-- 
James R. Van Artsdalen          james@bigtex.cactus.org   "Live Free or Die"
Dell Computer Co    9505 Arboretum Blvd Austin TX 78759         512-338-8789