From: hlu@luke.wsu.edu (H.J. Lu) Subject: ANNOUNCE: One more __load.o in libc.sa is fixed Date: 17 Feb 1993 08:04:36 GMT
The image-4.3.tar.z on tsx-11 has been fixed.
H.J.
=====
I have put new image-4.3.tar.z, extra-4.3.tar.z, libc-4.3.tar.z and
libc-4.2-4.3.tar.z on tsx-11 under pub/linux/GCC. If you have already
got them from tsx-11, you don't have to re-download everything. You
can do
A. For the shared stub and static C libraries, do
gcc -Wall -O6 -fomit-frame-pointer -c __load.c
ar -d /usr/lib/libc.sa __.SYMDEF
ar ucv /usr/lib/libc.sa __load.o
ranlib /usr/lib/libc.sa
ar -d /usr/lib/libc.a __.SYMDEF
ar ucv /usr/lib/libc.a __load.o
ranlib /usr/lib/libc.a
B. For profiling C library, do
gcc -Wall -O -pg -c __load.c
ar -d /usr/lib/libc_p.a __.SYMDEF
ar ucv /usr/lib/libc_p.a __load.o
ranlib /usr/lib/libc_p.a
C. For debugging C library, do
gcc -Wall -O -g -c __load.c
ar -d /usr/lib/libg.a __.SYMDEF
ar ucv /usr/lib/libg.a __load.o
ranlib /usr/lib/libg.a
H.J.
hlu@eecs.wsu.edu
02/16/93
===========
From: eric@tantalus.nrl.navy.mil (Eric Youngdale)
Subject: Bug in dynamic linking - only affects emacs.
I have discovered a bug in the dynamic linking, but as far as I can
tell the only effect that it has is that you cannot link emacs. The patch is
relatively simple, and only covers __load.c, so that no sharable images will
need to be relinked. You will just need to compile __load.c (enclosed) and
use "ar" to insert it in /usr/lib/libc.sa.
Basically the problem is that there is a magic number in the dynamic
linking tables that is used to verify that we are looking at the correct
information, and this number is incremented as we go through the various phases
of dynamic linking. Emacs actually runs twice - the first time we simply load
up a lot of lisp code, and then we effectively dump memory to a file which is
the usual "emacs" executable that we all know and love. When we dump the
binary, the modified magic numbers are also stored, and thus when we run the
dumped emacs, the dynamic linking code sees the modified magic numbers and
thinks that something is screwed up so it exits instead of continuing on.
I have added a simple subroutine that resets the magic numbers back to
the original values, and it seems to work, at least in part. The emacs binary
that I generated is unable to load up normal text files, but I had to hack
things quite a bit in order to get it to compile. The thing that I suspect the
most strongly is the "#define const " in s-linux.h - I had to take this out
because there were conflicting definitions for various functions, some had
const and others had __const, and GCC squalked. I will leave these issues for
someone else to deal with, since I have now gotten the binary to load properly.
Did you know that you can compile emacs in under 6Mb disk space, if the
sources are on a cdrom and you use lndir to set up gobs of symbolic links :-)??
It is a bit slower than it would otherwise be, but it gets the job done.
-Eric
==========CUT HERE for libc=linux/sysdeps/linux/__load.c =====
static int errno = 0;
#include <unistd.h>
#include <syscall.h>
#include <stdarg.h>
#include <sharedlib.h>
#include <errno.h>
static inline volatile void
_call_exit(int exit_code)
{
__asm__("int $0x80"::"a" (SYS_exit),"b" (exit_code):"bx");
}
static inline volatile int
_call_uselib(const char * filename)
{
__asm__("int $0x80"::"a" (SYS_uselib),"b" (filename):"bx");
}
static
_syscall3(ssize_t,write,int,fd,const void *,buf,size_t,count)
static inline int
length(const char *str)
{
const char *p;
for (p = str; *p; p++);
return p - str;
}
static void
__lib_print (int fd, ...)
{
char *cp;
va_list ap;
va_start(ap, fd);
for (cp = va_arg(ap, char *); cp; cp = va_arg(ap, char *))
write (fd, cp, length(cp));
va_end(ap);
}
static inline void
__shlib_fatal (const char *argv0, const char *lib, int err)
{
__lib_print (2, argv0, ": can't load library '", lib, "'\n\t",
NULL);
switch (err) {
case 0:
__lib_print (2, "Incompatible version.\n", NULL);
break;
case EINVAL:
__lib_print (2, "Too many libraries.\n", NULL);
break;
case ENOENT:
__lib_print (2, "No such library.\n", NULL);
break;
case EACCES:
__lib_print (2, "Permission denied.\n", NULL);
break;
case ENOEXEC:
__lib_print (2, "Exec format error.\n", NULL);
break;
default:
__lib_print (2, "Unspecified error.\n", NULL);
break;
}
while (1)
_call_exit (128);
}
static inline int
incompatible(int in_core, int linked)
{
if (linked & CLASSIC_BIT) {
return (in_core != linked);
}
else {
return ((in_core & MAJOR_MASK) != (linked & MAJOR_MASK) ||
(in_core & MINOR_MASK) < (linked & MINOR_MASK));
}
}
/* This list is generated by the linker - it corresponds to the SETD
list generated in conjunction with the variable __SHARABLE_CONFLICTS__.
The linker does not do anything special with this symbol - it simply
puts together the pieces that are needed. The list of fixups to local
variables is generated internally by the linker, and ld fills in this
one field as a special case before writing the image. The array size
is listed as 1, but it would actually be ->size - 2. __load.c will
pick up this pointer and pass it to __dynamic_resolve() and __do_fixups().
*/
struct fixuplist{ /* This list is generated by the linker */
int size;
int * magic; /* Used for verification purposes */
struct image_fixuplist * list; /* Fixups to local variables */
struct fixuplist *** shrlib_list[1]; /* One for each sharable
library this program is linked to. The sharable libraries
are linked to other sharable libraries, so we have to walk
this tree and resolve all of the fixups. */
};
/* This is a linker-generated list of fixups. The linker essentially
watches for multiple definitions of symbols, and if there is a
__GOT__ symbol then it does not flag an error condition. Instead, it
adds a fixup to the fixuplist which will correct the __GOT__ that
appears later on the link command line. The number of pointer pairs
is always specified by the size field, and after the last pointer pair
is the pointer to the builtin_fixups.
*/
struct image_fixuplist{
int size;
struct elemental_fixup{
union{
int newaddr;
struct builtin_fixup* bifu;
}un;
int * fixaddr;
} fix[1];
};
/* Each link image (sharable libraries are each considered a sharable
link image) will have a list of builtin fixups as well, as many as one
for each source file that went into the link image. These lists
are generated by jumpas as needed (perhaps one per source file), and a SETD
symbol __BUILTIN_FIXUPS__. These will never appear in a user program -
only in a shared library. This structure contains a series of pointers
to these different lists, and we need to walk through and apply all
of the fixups. The array size is listed as 1, but it can be any number
*/
struct builtin_fixup{
int len;
struct file_fixup * fixpnt[1]; /* Potentially one for every source
file that was linked */
};
/* Each source file can potentially have one of these beasts. There
are a series of pointer pairs, terminated by a NULL. The idea here is
that we are supposed to copy the number out of gotaddr and store it at
fixaddr. This is the list that is generated by the jumpas tool.
This is listed with an array size of 1, but it can be any number.
*/
struct file_fixup{
struct builtin_elemental_fixup{
int * gotaddr;
int * fixaddr;
} fixup[1];
};
extern struct libentry * __SHARED_LIBRARIES__[];
extern struct fixuplist _SHARABLE_CONFLICTS__;
/* Here we fix addresses of global variables that are stored in the
data section (or stored as data in the text section).d We wait to
do this until after all of the GOT pointers have been updated by
__dynamic_resolve because this is where we are copying our numbers
from */
static void __reset_magic(struct fixuplist * xpnt)
{
int size;
/* Now go back through and reset the magic numbers. The only reason we
need to do this is that we must allow for the possiblility of the
memory image being dumped to a new executable (i.e. emacs). */
if(*xpnt->magic == 0xfeeb1ed3) return; /* This means we have been through
here before */
if(*xpnt->magic != 0xfeeb1ed6) {
__lib_print (2, "Corrupt fixup table.\n", NULL);
exit(128);
};
(*xpnt->magic) = 0xfeeb1ed3; /* Reset back to the original value */
size = (unsigned int) xpnt->size - 3;
/* First recurse through the various shared libraries we are linked to */
while(size >= 0)
__reset_magic(**xpnt->shrlib_list[size--]);
}
static void __do_fixups(struct fixuplist * xpnt, int flag)
{
int size;
struct builtin_fixup * bpnt;
/* Now we walk through the list of pointers that need to be updated.
This is essentially our dynamic linking. Strictly speaking this is
somewhat simpler, because all we are really doing is fixing the scope
of variables and functions so that functions are used in the same
was as they would be if we were linked statically.
*/
if(*xpnt->magic == 0xfeeb1ed4 + (flag << 1)) return; /* This means we have been through
here before */
if(*xpnt->magic != 0xfeeb1ed3 + (flag << 1)) {
__lib_print (2, "Corrupt fixup table.\n", NULL);
exit(128);
};
(*xpnt->magic)++; /* This is so we know if we have been
through here before */
size = (unsigned int) xpnt->size - 3;
/* First recurse through the various shared libraries we are linked to */
while(size >= 0)
__do_fixups(**xpnt->shrlib_list[size--], flag);
/* Now get the pointer to the builtin fixups. */
bpnt = xpnt->list->fix[xpnt->list->size].un.bifu;
/* If there are fixups, then we scan through the various files that
have tables, and apply all of the fixups in the table. Consider that
an address could be stored as:
.long _foo+3
we allow for the offset by first subracting the value of _foo that
the linker assigned, then using __dynamic_resolve to fix all of the
GOT entries that need to be fixed, and then adding in the new offset
of the (possibly) new value of _foo
*/
if(bpnt)
for(size = 0; size < bpnt->len; size++) {
int i = 0;
struct file_fixup * fpnt;
fpnt = bpnt->fixpnt[size];
while(1==1){
if(!fpnt->fixup[i].gotaddr) break;
if(!flag)
*fpnt->fixup[i].fixaddr -= *fpnt->fixup[i].gotaddr;
else
*fpnt->fixup[i].fixaddr += *fpnt->fixup[i].gotaddr;
i++;
};
};
}
static void __dynamic_resolve(struct fixuplist * xpnt)
{
/* Now we walk through the list of pointers that need to be updated.
This is essentially our dynamic linking. Strictly speaking this is
somewhat simpler, because all we are really doing is fixing the scope
of variables and functions so that functions are used in the same
was as they would be if we were linked statically.
*/
int size;
/* Check for the magic number to make sure that we really have a proper
fixup table */
if(*xpnt->magic == 0xfeeb1ed5) return; /* This means we have been through
here before */
if(*xpnt->magic != 0xfeeb1ed4) {
__lib_print (2, "Corrupt fixup table.\n", NULL);
exit(128);
};
(*xpnt->magic)++; /* This is so we catch circularly linked libraries */
size = (unsigned int) xpnt->size - 3;
/* Recurse through the shared libraries, one by one */
while(size >= 0)
__dynamic_resolve(**xpnt->shrlib_list[size--]);
/* Now that this is done, perform the fixups that were generated
when this image was linked. */
for(size = 0; size < xpnt->list->size; size++) {
if(!xpnt->list->fix[size].un.newaddr) break;
*xpnt->list->fix[size].fixaddr = xpnt->list->fix[size].un.newaddr;
};
/* Now handle the linker-identified fixups. These are listed as a
pair of GOT addresses - the difference is that these are represent a
pair of pointers to GOT entries rather than a new address and a GOT
address. There are a pair of longword NULL pointers that separate the
linker identified fixups from the linker identified places where we
simply copy a pointer. We are effectively replacing pointers in the
GOT variables here. */
while (++size < xpnt->list->size){
*xpnt->list->fix[size].fixaddr =
*((int *) xpnt->list->fix[size].un.newaddr);
size++;
};
}
void
__load_shared_libraries (int argc, char **argv)
{
struct libentry **ptr;
if (argc > 0) {
for (ptr = __SHARED_LIBRARIES__+2; *ptr; ptr++)
{
unsigned *vers = (unsigned *)(*ptr)->addr;
if (_call_uselib((*ptr)->name))
__shlib_fatal (argv [0], (*ptr)->name, errno);
if (incompatible(*vers, (*ptr)->vers))
__shlib_fatal (argv [0], (*ptr)->name, 0);
}
}
else {
for (ptr = __SHARED_LIBRARIES__+2; *ptr; ptr++)
__lib_print (1, "\t", (*ptr)->name, " (", (*ptr)->avers, ")\n", NULL);
while (1) _call_exit (0);
}
/* Subtract curr addr from .long _foo */
__do_fixups(&_SHARABLE_CONFLICTS__, 0);
__dynamic_resolve (&_SHARABLE_CONFLICTS__);
/* Add (possibly) new addr to .long _foo */
__do_fixups(&_SHARABLE_CONFLICTS__, 1);
/* Set the magic numbers back to the starting values for emacs */
__reset_magic(&_SHARABLE_CONFLICTS__);
}