Ld directory reorganization:
- separate out the common files used by rtld ldd ld - move machine dependent files into arch - move ld in its own directory - factor out .PATH and CFLAGS common to all Makefiles
This commit is contained in:
parent
b4f53dbf7c
commit
d3d1227320
@ -1,15 +1,6 @@
|
||||
# $NetBSD: Makefile,v 1.14 1997/03/24 19:54:35 perry Exp $
|
||||
# $NetBSD: Makefile,v 1.15 1997/04/16 16:49:28 christos Exp $
|
||||
|
||||
PROG= ld
|
||||
SRCS= ld.c symbol.c lib.c shlib.c warnings.c etc.c rrs.c xbits.c md.c
|
||||
CFLAGS += -g -I$(.CURDIR) -I$(.CURDIR)/$(MACHINE_ARCH)
|
||||
|
||||
LDADD+= -lgnumalloc
|
||||
DPADD+= /usr/lib/libgnumalloc.a
|
||||
|
||||
SUBDIR= ldconfig ldd
|
||||
|
||||
.PATH: $(.CURDIR)/$(MACHINE_ARCH)
|
||||
SUBDIR= ld ldconfig ldd
|
||||
|
||||
.include <bsd.own.mk> # for NOPIC definition
|
||||
|
||||
|
5
gnu/usr.bin/ld/Makefile.inc
Normal file
5
gnu/usr.bin/ld/Makefile.inc
Normal file
@ -0,0 +1,5 @@
|
||||
# $NetBSD: Makefile.inc,v 1.1 1997/04/16 16:49:29 christos Exp $
|
||||
|
||||
CFLAGS += -I$(.CURDIR)/../common -I$(.CURDIR)/../arch/$(MACHINE_ARCH)
|
||||
|
||||
.PATH: $(.CURDIR)/../common $(.CURDIR)/../arch/$(MACHINE_ARCH)
|
@ -1,975 +0,0 @@
|
||||
/*-
|
||||
* This code is derived from software copyrighted by the Free Software
|
||||
* Foundation.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
/*static char sccsid[] = "from: @(#)cplus-dem.c 5.4 (Berkeley) 4/30/91";*/
|
||||
static char rcsid[] = "$Id: cplus-dem.c,v 1.2 1993/08/01 18:46:58 mycroft Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/* Demangler for GNU C++
|
||||
Copyright (C) 1989 Free Software Foundation, Inc.
|
||||
written by James Clark (jjc@jclark.uucp)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* This is for g++ 1.36.1 (November 6 version). It will probably
|
||||
require changes for any other version.
|
||||
|
||||
Modified for g++ 1.36.2 (November 18 version). */
|
||||
|
||||
/* This file exports one function
|
||||
|
||||
char *cplus_demangle (const char *name)
|
||||
|
||||
If `name' is a mangled function name produced by g++, then
|
||||
a pointer to a malloced string giving a C++ representation
|
||||
of the name will be returned; otherwise NULL will be returned.
|
||||
It is the caller's responsibility to free the string which
|
||||
is returned.
|
||||
|
||||
For example,
|
||||
|
||||
cplus_demangle ("_foo__1Ai")
|
||||
|
||||
returns
|
||||
|
||||
"A::foo(int)"
|
||||
|
||||
This file imports xmalloc and xrealloc, which are like malloc and
|
||||
realloc except that they generate a fatal error if there is no
|
||||
available memory. */
|
||||
|
||||
/* #define nounderscore 1 /* define this is names don't start with _ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef USG
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#else
|
||||
#include <strings.h>
|
||||
#define memcpy(s1, s2, n) bcopy ((s2), (s1), (n))
|
||||
#define memcmp(s1, s2, n) bcmp ((s2), (s1), (n))
|
||||
#define strchr index
|
||||
#define strrchr rindex
|
||||
#endif
|
||||
|
||||
#ifndef __STDC__
|
||||
#define const
|
||||
#endif
|
||||
|
||||
#ifdef __STDC__
|
||||
extern char *cplus_demangle (const char *type);
|
||||
#else
|
||||
extern char *cplus_demangle ();
|
||||
#endif
|
||||
|
||||
#ifdef __STDC__
|
||||
extern char *xmalloc (int);
|
||||
extern char *xrealloc (char *, int);
|
||||
#else
|
||||
extern char *xmalloc ();
|
||||
extern char *xrealloc ();
|
||||
#endif
|
||||
|
||||
static char **typevec = 0;
|
||||
static int ntypes = 0;
|
||||
static int typevec_size = 0;
|
||||
|
||||
static struct {
|
||||
const char *in;
|
||||
const char *out;
|
||||
} optable[] = {
|
||||
"new", " new",
|
||||
"delete", " delete",
|
||||
"ne", "!=",
|
||||
"eq", "==",
|
||||
"ge", ">=",
|
||||
"gt", ">",
|
||||
"le", "<=",
|
||||
"lt", "<",
|
||||
"plus", "+",
|
||||
"minus", "-",
|
||||
"mult", "*",
|
||||
"convert", "+", /* unary + */
|
||||
"negate", "-", /* unary - */
|
||||
"trunc_mod", "%",
|
||||
"trunc_div", "/",
|
||||
"truth_andif", "&&",
|
||||
"truth_orif", "||",
|
||||
"truth_not", "!",
|
||||
"postincrement", "++",
|
||||
"postdecrement", "--",
|
||||
"bit_ior", "|",
|
||||
"bit_xor", "^",
|
||||
"bit_and", "&",
|
||||
"bit_not", "~",
|
||||
"call", "()",
|
||||
"cond", "?:",
|
||||
"alshift", "<<",
|
||||
"arshift", ">>",
|
||||
"component", "->",
|
||||
"indirect", "*",
|
||||
"method_call", "->()",
|
||||
"addr", "&", /* unary & */
|
||||
"array", "[]",
|
||||
"nop", "", /* for operator= */
|
||||
};
|
||||
|
||||
/* Beware: these aren't '\0' terminated. */
|
||||
|
||||
typedef struct {
|
||||
char *b; /* pointer to start of string */
|
||||
char *p; /* pointer after last character */
|
||||
char *e; /* pointer after end of allocated space */
|
||||
} string;
|
||||
|
||||
#ifdef __STDC__
|
||||
static void string_need (string *s, int n);
|
||||
static void string_delete (string *s);
|
||||
static void string_init (string *s);
|
||||
static void string_clear (string *s);
|
||||
static int string_empty (string *s);
|
||||
static void string_append (string *p, const char *s);
|
||||
static void string_appends (string *p, string *s);
|
||||
static void string_appendn (string *p, const char *s, int n);
|
||||
static void string_prepend (string *p, const char *s);
|
||||
#if 0
|
||||
static void string_prepends (string *p, string *s);
|
||||
#endif
|
||||
static void string_prependn (string *p, const char *s, int n);
|
||||
static int get_count (const char **type, int *count);
|
||||
static int do_args (const char **type, string *decl);
|
||||
static int do_type (const char **type, string *result);
|
||||
static int do_arg (const char **type, string *result);
|
||||
static int do_args (const char **type, string *decl);
|
||||
static void munge_function_name (string *name);
|
||||
static void remember_type (const char *type, int len);
|
||||
#else
|
||||
static void string_need ();
|
||||
static void string_delete ();
|
||||
static void string_init ();
|
||||
static void string_clear ();
|
||||
static int string_empty ();
|
||||
static void string_append ();
|
||||
static void string_appends ();
|
||||
static void string_appendn ();
|
||||
static void string_prepend ();
|
||||
static void string_prepends ();
|
||||
static void string_prependn ();
|
||||
static int get_count ();
|
||||
static int do_args ();
|
||||
static int do_type ();
|
||||
static int do_arg ();
|
||||
static int do_args ();
|
||||
static void munge_function_name ();
|
||||
static void remember_type ();
|
||||
#endif
|
||||
|
||||
char *
|
||||
cplus_demangle (type)
|
||||
const char *type;
|
||||
{
|
||||
string decl;
|
||||
int n;
|
||||
int success = 0;
|
||||
int constructor = 0;
|
||||
int const_flag = 0;
|
||||
int i;
|
||||
const char *p;
|
||||
#ifndef LONGERNAMES
|
||||
const char *premangle;
|
||||
#endif
|
||||
|
||||
if (type == NULL || *type == '\0')
|
||||
return NULL;
|
||||
#ifndef nounderscore
|
||||
if (*type++ != '_')
|
||||
return NULL;
|
||||
#endif
|
||||
p = type;
|
||||
while (*p != '\0' && !(*p == '_' && p[1] == '_'))
|
||||
p++;
|
||||
if (*p == '\0')
|
||||
{
|
||||
/* destructor */
|
||||
if (type[0] == '_' && type[1] == '$' && type[2] == '_')
|
||||
{
|
||||
int n = (strlen (type) - 3)*2 + 3 + 2 + 1;
|
||||
char *tem = (char *) xmalloc (n);
|
||||
strcpy (tem, type + 3);
|
||||
strcat (tem, "::~");
|
||||
strcat (tem, type + 3);
|
||||
strcat (tem, "()");
|
||||
return tem;
|
||||
}
|
||||
/* static data member */
|
||||
if (*type != '_' && (p = strchr (type, '$')) != NULL)
|
||||
{
|
||||
int n = strlen (type) + 2;
|
||||
char *tem = (char *) xmalloc (n);
|
||||
memcpy (tem, type, p - type);
|
||||
strcpy (tem + (p - type), "::");
|
||||
strcpy (tem + (p - type) + 2, p + 1);
|
||||
return tem;
|
||||
}
|
||||
/* virtual table */
|
||||
if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$')
|
||||
{
|
||||
int n = strlen (type + 4) + 14 + 1;
|
||||
char *tem = (char *) xmalloc (n);
|
||||
strcpy (tem, type + 4);
|
||||
strcat (tem, " virtual table");
|
||||
return tem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string_init (&decl);
|
||||
|
||||
if (p == type)
|
||||
{
|
||||
if (!isdigit (p[2]))
|
||||
{
|
||||
string_delete (&decl);
|
||||
return NULL;
|
||||
}
|
||||
constructor = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
string_appendn (&decl, type, p - type);
|
||||
munge_function_name (&decl);
|
||||
}
|
||||
p += 2;
|
||||
|
||||
#ifndef LONGERNAMES
|
||||
premangle = p;
|
||||
#endif
|
||||
switch (*p)
|
||||
{
|
||||
case 'C':
|
||||
/* a const member function */
|
||||
if (!isdigit (p[1]))
|
||||
{
|
||||
string_delete (&decl);
|
||||
return NULL;
|
||||
}
|
||||
p += 1;
|
||||
const_flag = 1;
|
||||
/* fall through */
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
n = 0;
|
||||
do
|
||||
{
|
||||
n *= 10;
|
||||
n += *p - '0';
|
||||
p += 1;
|
||||
}
|
||||
while (isdigit (*p));
|
||||
if (strlen (p) < n)
|
||||
{
|
||||
string_delete (&decl);
|
||||
return NULL;
|
||||
}
|
||||
if (constructor)
|
||||
{
|
||||
string_appendn (&decl, p, n);
|
||||
string_append (&decl, "::");
|
||||
string_appendn (&decl, p, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
string_prepend (&decl, "::");
|
||||
string_prependn (&decl, p, n);
|
||||
}
|
||||
p += n;
|
||||
#ifndef LONGERNAMES
|
||||
remember_type (premangle, p - premangle);
|
||||
#endif
|
||||
success = do_args (&p, &decl);
|
||||
if (const_flag)
|
||||
string_append (&decl, " const");
|
||||
break;
|
||||
case 'F':
|
||||
p += 1;
|
||||
success = do_args (&p, &decl);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ntypes; i++)
|
||||
if (typevec[i] != NULL)
|
||||
free (typevec[i]);
|
||||
ntypes = 0;
|
||||
if (typevec != NULL)
|
||||
{
|
||||
free ((char *)typevec);
|
||||
typevec = NULL;
|
||||
typevec_size = 0;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
string_appendn (&decl, "", 1);
|
||||
return decl.b;
|
||||
}
|
||||
else
|
||||
{
|
||||
string_delete (&decl);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
get_count (type, count)
|
||||
const char **type;
|
||||
int *count;
|
||||
{
|
||||
if (!isdigit (**type))
|
||||
return 0;
|
||||
*count = **type - '0';
|
||||
*type += 1;
|
||||
/* see flush_repeats in cplus-method.c */
|
||||
if (isdigit (**type))
|
||||
{
|
||||
const char *p = *type;
|
||||
int n = *count;
|
||||
do
|
||||
{
|
||||
n *= 10;
|
||||
n += *p - '0';
|
||||
p += 1;
|
||||
}
|
||||
while (isdigit (*p));
|
||||
if (*p == '_')
|
||||
{
|
||||
*type = p + 1;
|
||||
*count = n;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* result will be initialised here; it will be freed on failure */
|
||||
|
||||
static int
|
||||
do_type (type, result)
|
||||
const char **type;
|
||||
string *result;
|
||||
{
|
||||
int n;
|
||||
int done;
|
||||
int non_empty = 0;
|
||||
int success;
|
||||
string decl;
|
||||
const char *remembered_type;
|
||||
|
||||
string_init (&decl);
|
||||
string_init (result);
|
||||
|
||||
done = 0;
|
||||
success = 1;
|
||||
while (success && !done)
|
||||
{
|
||||
int member;
|
||||
switch (**type)
|
||||
{
|
||||
case 'P':
|
||||
*type += 1;
|
||||
string_prepend (&decl, "*");
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
*type += 1;
|
||||
string_prepend (&decl, "&");
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
*type += 1;
|
||||
if (!get_count (type, &n) || n >= ntypes)
|
||||
success = 0;
|
||||
else
|
||||
{
|
||||
remembered_type = typevec[n];
|
||||
type = &remembered_type;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
*type += 1;
|
||||
if (!string_empty (&decl) && decl.b[0] == '*')
|
||||
{
|
||||
string_prepend (&decl, "(");
|
||||
string_append (&decl, ")");
|
||||
}
|
||||
if (!do_args (type, &decl) || **type != '_')
|
||||
success = 0;
|
||||
else
|
||||
*type += 1;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
case 'O':
|
||||
{
|
||||
int constp = 0;
|
||||
int volatilep = 0;
|
||||
|
||||
member = **type == 'M';
|
||||
*type += 1;
|
||||
if (!isdigit (**type))
|
||||
{
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
n = 0;
|
||||
do
|
||||
{
|
||||
n *= 10;
|
||||
n += **type - '0';
|
||||
*type += 1;
|
||||
}
|
||||
while (isdigit (**type));
|
||||
if (strlen (*type) < n)
|
||||
{
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
string_append (&decl, ")");
|
||||
string_prepend (&decl, "::");
|
||||
string_prependn (&decl, *type, n);
|
||||
string_prepend (&decl, "(");
|
||||
*type += n;
|
||||
if (member)
|
||||
{
|
||||
if (**type == 'C')
|
||||
{
|
||||
*type += 1;
|
||||
constp = 1;
|
||||
}
|
||||
if (**type == 'V')
|
||||
{
|
||||
*type += 1;
|
||||
volatilep = 1;
|
||||
}
|
||||
if (*(*type)++ != 'F')
|
||||
{
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((member && !do_args (type, &decl)) || **type != '_')
|
||||
{
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
*type += 1;
|
||||
if (constp)
|
||||
{
|
||||
if (non_empty)
|
||||
string_append (&decl, " ");
|
||||
else
|
||||
non_empty = 1;
|
||||
string_append (&decl, "const");
|
||||
}
|
||||
if (volatilep)
|
||||
{
|
||||
if (non_empty)
|
||||
string_append (&decl, " ");
|
||||
else
|
||||
non_empty = 1;
|
||||
string_append (&decl, "volatilep");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'C':
|
||||
if ((*type)[1] == 'P')
|
||||
{
|
||||
*type += 1;
|
||||
if (!string_empty (&decl))
|
||||
string_prepend (&decl, " ");
|
||||
string_prepend (&decl, "const");
|
||||
break;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
default:
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done = 0;
|
||||
non_empty = 0;
|
||||
while (success && !done)
|
||||
{
|
||||
switch (**type)
|
||||
{
|
||||
case 'C':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
else
|
||||
non_empty = 1;
|
||||
string_append (result, "const");
|
||||
break;
|
||||
case 'U':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
else
|
||||
non_empty = 1;
|
||||
string_append (result, "unsigned");
|
||||
break;
|
||||
case 'V':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
else
|
||||
non_empty = 1;
|
||||
string_append (result, "volatile");
|
||||
break;
|
||||
default:
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
switch (**type)
|
||||
{
|
||||
case '\0':
|
||||
case '_':
|
||||
break;
|
||||
case 'v':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
string_append (result, "void");
|
||||
break;
|
||||
case 'x':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
string_append (result, "long long");
|
||||
break;
|
||||
case 'l':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
string_append (result, "long");
|
||||
break;
|
||||
case 'i':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
string_append (result, "int");
|
||||
break;
|
||||
case 's':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
string_append (result, "short");
|
||||
break;
|
||||
case 'c':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
string_append (result, "char");
|
||||
break;
|
||||
case 'r':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
string_append (result, "long double");
|
||||
break;
|
||||
case 'd':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
string_append (result, "double");
|
||||
break;
|
||||
case 'f':
|
||||
*type += 1;
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
string_append (result, "float");
|
||||
break;
|
||||
case 'G':
|
||||
*type += 1;
|
||||
if (!isdigit (**type))
|
||||
{
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
n = 0;
|
||||
do
|
||||
{
|
||||
n *= 10;
|
||||
n += **type - '0';
|
||||
*type += 1;
|
||||
}
|
||||
while (isdigit (**type));
|
||||
if (strlen (*type) < n)
|
||||
{
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
if (non_empty)
|
||||
string_append (result, " ");
|
||||
string_appendn (result, *type, n);
|
||||
*type += n;
|
||||
break;
|
||||
default:
|
||||
success = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (!string_empty (&decl))
|
||||
{
|
||||
string_append (result, " ");
|
||||
string_appends (result, &decl);
|
||||
}
|
||||
string_delete (&decl);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
string_delete (&decl);
|
||||
string_delete (result);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* `result' will be initialised in do_type; it will be freed on failure */
|
||||
|
||||
static int
|
||||
do_arg (type, result)
|
||||
const char **type;
|
||||
string *result;
|
||||
{
|
||||
const char *start = *type;
|
||||
|
||||
if (!do_type (type, result))
|
||||
return 0;
|
||||
remember_type (start, *type - start);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
remember_type (start, len)
|
||||
const char *start;
|
||||
int len;
|
||||
{
|
||||
char *tem;
|
||||
|
||||
if (ntypes >= typevec_size)
|
||||
{
|
||||
if (typevec_size == 0)
|
||||
{
|
||||
typevec_size = 3;
|
||||
typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
typevec_size *= 2;
|
||||
typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
|
||||
}
|
||||
}
|
||||
tem = (char *) xmalloc (len + 1);
|
||||
memcpy (tem, start, len);
|
||||
tem[len] = '\0';
|
||||
typevec[ntypes++] = tem;
|
||||
}
|
||||
|
||||
/* `decl' must be already initialised, usually non-empty;
|
||||
it won't be freed on failure */
|
||||
|
||||
static int
|
||||
do_args (type, decl)
|
||||
const char **type;
|
||||
string *decl;
|
||||
{
|
||||
string arg;
|
||||
int need_comma = 0;
|
||||
|
||||
string_append (decl, "(");
|
||||
|
||||
while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
|
||||
{
|
||||
if (**type == 'N')
|
||||
{
|
||||
int r;
|
||||
int t;
|
||||
*type += 1;
|
||||
if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
|
||||
return 0;
|
||||
while (--r >= 0)
|
||||
{
|
||||
const char *tem = typevec[t];
|
||||
if (need_comma)
|
||||
string_append (decl, ", ");
|
||||
if (!do_arg (&tem, &arg))
|
||||
return 0;
|
||||
string_appends (decl, &arg);
|
||||
string_delete (&arg);
|
||||
need_comma = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (need_comma)
|
||||
string_append (decl, ", ");
|
||||
if (!do_arg (type, &arg))
|
||||
return 0;
|
||||
string_appends (decl, &arg);
|
||||
string_delete (&arg);
|
||||
need_comma = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (**type == 'v')
|
||||
*type += 1;
|
||||
else if (**type == 'e')
|
||||
{
|
||||
*type += 1;
|
||||
if (need_comma)
|
||||
string_append (decl, ",");
|
||||
string_append (decl, "...");
|
||||
}
|
||||
|
||||
string_append (decl, ")");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
munge_function_name (name)
|
||||
string *name;
|
||||
{
|
||||
if (!string_empty (name) && name->p - name->b >= 3
|
||||
&& name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
|
||||
{
|
||||
int i;
|
||||
/* see if it's an assignment expression */
|
||||
if (name->p - name->b >= 10 /* op$assign_ */
|
||||
&& memcmp (name->b + 3, "assign_", 7) == 0)
|
||||
{
|
||||
for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
|
||||
{
|
||||
int len = name->p - name->b - 10;
|
||||
if (strlen (optable[i].in) == len
|
||||
&& memcmp (optable[i].in, name->b + 10, len) == 0)
|
||||
{
|
||||
string_clear (name);
|
||||
string_append (name, "operator");
|
||||
string_append (name, optable[i].out);
|
||||
string_append (name, "=");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
|
||||
{
|
||||
int len = name->p - name->b - 3;
|
||||
if (strlen (optable[i].in) == len
|
||||
&& memcmp (optable[i].in, name->b + 3, len) == 0)
|
||||
{
|
||||
string_clear (name);
|
||||
string_append (name, "operator");
|
||||
string_append (name, optable[i].out);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (!string_empty (name) && name->p - name->b >= 5
|
||||
&& memcmp (name->b, "type$", 5) == 0)
|
||||
{
|
||||
/* type conversion operator */
|
||||
string type;
|
||||
const char *tem = name->b + 5;
|
||||
if (do_type (&tem, &type))
|
||||
{
|
||||
string_clear (name);
|
||||
string_append (name, "operator ");
|
||||
string_appends (name, &type);
|
||||
string_delete (&type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* a mini string-handling package */
|
||||
|
||||
static void
|
||||
string_need (s, n)
|
||||
string *s;
|
||||
int n;
|
||||
{
|
||||
if (s->b == NULL)
|
||||
{
|
||||
if (n < 32)
|
||||
n = 32;
|
||||
s->p = s->b = (char *) xmalloc (n);
|
||||
s->e = s->b + n;
|
||||
}
|
||||
else if (s->e - s->p < n)
|
||||
{
|
||||
int tem = s->p - s->b;
|
||||
n += tem;
|
||||
n *= 2;
|
||||
s->b = (char *) xrealloc (s->b, n);
|
||||
s->p = s->b + tem;
|
||||
s->e = s->b + n;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
string_delete (s)
|
||||
string *s;
|
||||
{
|
||||
if (s->b != NULL)
|
||||
{
|
||||
free (s->b);
|
||||
s->b = s->e = s->p = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
string_init (s)
|
||||
string *s;
|
||||
{
|
||||
s->b = s->p = s->e = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
string_clear (s)
|
||||
string *s;
|
||||
{
|
||||
s->p = s->b;
|
||||
}
|
||||
|
||||
static int
|
||||
string_empty (s)
|
||||
string *s;
|
||||
{
|
||||
return s->b == s->p;
|
||||
}
|
||||
|
||||
static void
|
||||
string_append (p, s)
|
||||
string *p;
|
||||
const char *s;
|
||||
{
|
||||
int n;
|
||||
if (s == NULL || *s == '\0')
|
||||
return;
|
||||
n = strlen (s);
|
||||
string_need (p, n);
|
||||
memcpy (p->p, s, n);
|
||||
p->p += n;
|
||||
}
|
||||
|
||||
static void
|
||||
string_appends (p, s)
|
||||
string *p, *s;
|
||||
{
|
||||
int n;
|
||||
if (s->b == s->p)
|
||||
return;
|
||||
n = s->p - s->b;
|
||||
string_need (p, n);
|
||||
memcpy (p->p, s->b, n);
|
||||
p->p += n;
|
||||
}
|
||||
|
||||
static void
|
||||
string_appendn (p, s, n)
|
||||
string *p;
|
||||
const char *s;
|
||||
int n;
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
string_need (p, n);
|
||||
memcpy (p->p, s, n);
|
||||
p->p += n;
|
||||
}
|
||||
|
||||
static void
|
||||
string_prepend (p, s)
|
||||
string *p;
|
||||
const char *s;
|
||||
{
|
||||
if (s == NULL || *s == '\0')
|
||||
return;
|
||||
string_prependn (p, s, strlen (s));
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
string_prepends (p, s)
|
||||
string *p, *s;
|
||||
{
|
||||
if (s->b == s->p)
|
||||
return;
|
||||
string_prependn (p, s->b, s->p - s->b);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
string_prependn (p, s, n)
|
||||
string *p;
|
||||
const char *s;
|
||||
int n;
|
||||
{
|
||||
char *q;
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
string_need (p, n);
|
||||
for (q = p->p - 1; q >= p->b; q--)
|
||||
q[n] = q[0];
|
||||
memcpy (p->b, s, n);
|
||||
p->p += n;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* $Id: etc.c,v 1.7 1994/06/10 15:16:04 pk Exp $
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Like malloc but get fatal error if memory is exhausted.
|
||||
*/
|
||||
void *
|
||||
xmalloc(size)
|
||||
size_t size;
|
||||
{
|
||||
register void *result = (void *)malloc(size);
|
||||
|
||||
if (!result)
|
||||
errx(1, "virtual memory exhausted");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like realloc but get fatal error if memory is exhausted.
|
||||
*/
|
||||
void *
|
||||
xrealloc(ptr, size)
|
||||
void *ptr;
|
||||
size_t size;
|
||||
{
|
||||
register void *result;
|
||||
|
||||
if (ptr == NULL)
|
||||
result = (void *)malloc(size);
|
||||
else
|
||||
result = (void *)realloc(ptr, size);
|
||||
|
||||
if (!result)
|
||||
errx(1, "virtual memory exhausted");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a newly-allocated string whose contents concatenate
|
||||
* the strings S1, S2, S3.
|
||||
*/
|
||||
char *
|
||||
concat(s1, s2, s3)
|
||||
const char *s1, *s2, *s3;
|
||||
{
|
||||
register int len1 = strlen(s1),
|
||||
len2 = strlen(s2),
|
||||
len3 = strlen(s3);
|
||||
|
||||
register char *result = (char *)xmalloc(len1 + len2 + len3 + 1);
|
||||
|
||||
strcpy(result, s1);
|
||||
strcpy(result + len1, s2);
|
||||
strcpy(result + len1 + len2, s3);
|
||||
result[len1 + len2 + len3] = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -1,259 +0,0 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1993 Paul Kranenburg
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by Paul Kranenburg.
|
||||
.\" 3. The name of the author may not be used to endorse or promote products
|
||||
.\" derived from this software without specific prior written permission
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (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: ld.1,v 1.11 1996/12/04 00:11:23 perry Exp $
|
||||
.\"
|
||||
.Dd October 14, 1993
|
||||
.Dt LD 1
|
||||
.Os NetBSD
|
||||
.Sh NAME
|
||||
.Nm ld
|
||||
.Nd link editor
|
||||
.Sh SYNOPSIS
|
||||
.Nm ld
|
||||
.Op Fl MNnrSstXxz
|
||||
.Bk -words
|
||||
.Op Fl A Ar symbol-file
|
||||
.Op Fl assert Ar keyword
|
||||
.Op Fl B Ns Ar linkmode
|
||||
.Op Fl D Ar datasize
|
||||
.Op Fl d Ar c
|
||||
.Op Fl d Ar p
|
||||
.Op Fl e Ar entry
|
||||
.Op Fl l Ns Ar library-specifier
|
||||
.Op Fl L Ns Ar library-search-path
|
||||
.Op Fl nostdlib
|
||||
.Op Fl o Ar filename
|
||||
.Op Fl T Ar address
|
||||
.Op Fl u Ar symbol
|
||||
.Op Fl V Ar shlib-version
|
||||
.Op Fl y Ar symbol
|
||||
.Ek
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
combines the object and archive files given on the command line into a new
|
||||
object file. The output object file is either an executable program, a
|
||||
shared object suitable for loading at run-time, or an object file that can
|
||||
once again be processed by
|
||||
.Nm ld.
|
||||
Object files and archives are processed in the order given on the command line.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Pp
|
||||
.Bl -tag -width indent
|
||||
.It Fl A Ar symbol-file
|
||||
The symbol-file is taken as a base for link-editing the object files
|
||||
on the command line.
|
||||
.It Fl assert Ar keyword
|
||||
This option has currently no effect. It is here for compatibility with
|
||||
SunOS ld. All conditions which would cause a Sun assertion to fail will
|
||||
currently always cause error or warning messages from
|
||||
.Nm ld .
|
||||
.It Fl B Ns Ar dynamic
|
||||
Specifies that linking against dynamic libraries can take place. If a library
|
||||
specifier of the form -lx appears on the command line,
|
||||
.Nm ld
|
||||
searches for a library of the from libx.so.n.m
|
||||
.Po see the \&
|
||||
.Fl l
|
||||
option
|
||||
.Pc
|
||||
according to the search rules in effect. If such a file can not be
|
||||
found a traditional archive is looked for.
|
||||
This options can appear anywhere on the command line and is complementary
|
||||
to
|
||||
.Fl B Ns Ar static .
|
||||
.It Fl B Ns Ar static
|
||||
The counterpart of
|
||||
.Fl B Ns Ar dynamic .
|
||||
This option turns off dynamic linking for
|
||||
all library specifiers until a
|
||||
.Fl B Ns Ar dynamic
|
||||
is once again given. Any explicitly
|
||||
mentioned shared object encountered on the command line while this option is
|
||||
in effect is flagged as an error.
|
||||
.It Fl B Ns Ar shareable
|
||||
Instructs the linker to build a shared object from the object files rather
|
||||
than a normal executable image.
|
||||
.It Fl B Ns Ar symbolic
|
||||
This option causes all symbolic references in the output to be resolved in
|
||||
this link-edit session. The only remaining run-time relocation requirements are
|
||||
.Em base-relative
|
||||
relocations, ie. translation with respect to the load address. Failure to
|
||||
resolve any symbolic reference causes an error to be reported.
|
||||
.It Fl B Ns Ar forcearchive
|
||||
Force all members of archives to be loaded, whether or not such members
|
||||
contribute a definition to any plain object files. Useful for making a
|
||||
shared library from an archive of PIC objects without having to unpack
|
||||
the archive.
|
||||
.It Fl B Ns Ar silly
|
||||
Search for
|
||||
.Em \.sa
|
||||
silly archive companions of shared objects. Useful for compatibility with
|
||||
version 3 shared objects.
|
||||
.It Fl D Ar data-size
|
||||
Set the size of the data segment. For sanity's sake, this should be larger
|
||||
than the cumulative data sizes of the input files.
|
||||
.It Fl d Ar c
|
||||
Force allocation of commons even producing relocatable output.
|
||||
.It Fl d Ar p
|
||||
Force alias definitions of procedure calls in non-PIC code. Useful to
|
||||
obtain shareable code in the presence of run-time relocations as such
|
||||
calls will be re-directed through the Procedure Linkage Table (see
|
||||
.Xr link 5 )
|
||||
.It Fl e Ar entry-symbol
|
||||
Specifies the entry symbol for an executable.
|
||||
.It Fl L Ns Ar path
|
||||
Add
|
||||
.Ar path
|
||||
to the list of directories to search for libraries specified with the
|
||||
.Ar -l
|
||||
option.
|
||||
.It Fl l Ns Ar lib-spec
|
||||
This option specifies a library to be considered for inclusion in the
|
||||
output. If the
|
||||
.Fl B Ns Ar dynamic
|
||||
option is in effect, a shared library of the
|
||||
form lib<spec>.so.m.n
|
||||
.Po where \&
|
||||
.Em m
|
||||
is the major, and
|
||||
.Em n
|
||||
is the minor version number, respectively
|
||||
.Pc is searched for first. The
|
||||
library with the highest version found in the search path is selected.
|
||||
If no shared library is found or the
|
||||
.Fl B Ns Ar static
|
||||
option is in effect, an archive of the form lib<spec>.a is looked for in
|
||||
the library search path.
|
||||
.It Fl M
|
||||
Produce output about the mapping of segments of the input files and the
|
||||
values assigned to
|
||||
.Pq global
|
||||
symbols in the output file.
|
||||
.It Fl N
|
||||
Produce a
|
||||
.Dv OMAGIC
|
||||
output file.
|
||||
.It Fl n
|
||||
Produce a
|
||||
.Dv NMAGIC
|
||||
output file.
|
||||
.It Fl nostdlib
|
||||
Do not search the built-in path
|
||||
.Po
|
||||
usually
|
||||
.Dq /usr/lib
|
||||
.Pc
|
||||
for
|
||||
.Fl l
|
||||
specified libraries.
|
||||
.It Fl o Ar filename
|
||||
Specifies the name of the output file. Defaults to
|
||||
.Dq a.out .
|
||||
.It Fl Q
|
||||
Produce a
|
||||
.Dv QMAGIC
|
||||
output file.
|
||||
.It Fl r
|
||||
Produce relocatable object file, suitable for another pass through
|
||||
.Nm ld .
|
||||
.It Fl R
|
||||
Record the given path within the executable for run-time libary search.
|
||||
This only applies to dynamically linked executables.
|
||||
.It Fl S
|
||||
Strip all debugger symbols from the output.
|
||||
.It Fl s
|
||||
Strip all symbols from the output.
|
||||
.It Fl T
|
||||
Specifies the start address of the text segment, with respect to which
|
||||
all input files will be relocated.
|
||||
.It Fl t
|
||||
Leave a trace of the input files as they are processed.
|
||||
.It Fl u Ar symbol
|
||||
Force
|
||||
.Ar symbol
|
||||
to be marked as undefined. Useful to force loading of an archive member
|
||||
in the absence of any other references to that member.
|
||||
.It Fl V Ar version
|
||||
Put the given version number into the output shared library
|
||||
.Pq if one is created .
|
||||
Useful to make shared libaries compatible with other operating
|
||||
systems. Eg. SunOS 4.x libraries use version number 3. Defaults to 8.
|
||||
.It Fl X
|
||||
Discard local symbols in the input files that start with the letter
|
||||
.Dq L
|
||||
.It Fl x
|
||||
Discard all local symbols in the input files.
|
||||
.It Fl y Ar symbol
|
||||
Trace the manipulations inflicted on
|
||||
.Ar symbol
|
||||
.It Fl z
|
||||
Make a
|
||||
.Dv ZMAGIC
|
||||
output file. This is the default.
|
||||
.Sh ENVIRONMENT
|
||||
.Nm
|
||||
utilizes the following environment variables:
|
||||
.Bl -tag -width "LD_LIBRARY_PATH"
|
||||
.It Ev LD_LIBRARY_PATH
|
||||
This colon-separated list of directories is inserted into the search
|
||||
path for libraries following any directories specified via
|
||||
.Fl L
|
||||
options and preceding the built-in path.
|
||||
.It Ev LD_NOSTD_PATH
|
||||
When set, do not search the built-in path for libraries.
|
||||
This is an alternative to the
|
||||
.Fl nostdlib
|
||||
command-line flag.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Sh SEE ALSO
|
||||
.Xr ldconfig 1 ,
|
||||
.Xr ld.so 1 ,
|
||||
.Xr link 5
|
||||
.Sh CAVEATS
|
||||
An entry point must now explicitly be given if the output is intended to be
|
||||
a normal executable program. This was not the case for the previous version of
|
||||
.Nm ld .
|
||||
.Sh BUGS
|
||||
Shared objects are not properly checked for undefined symbols.
|
||||
.Pp
|
||||
Cascading of shared object defeats the
|
||||
.Dq -Bstatic
|
||||
option.
|
||||
.Pp
|
||||
All shared objects presented to
|
||||
.Nm ld
|
||||
are marked for run-time loading in the output file, even if no symbols
|
||||
are needed from them.
|
||||
.Sh HISTORY
|
||||
The shared library model employed by
|
||||
.Nm ld
|
||||
appeared first in SunOS 4.0.
|
3746
gnu/usr.bin/ld/ld.c
3746
gnu/usr.bin/ld/ld.c
File diff suppressed because it is too large
Load Diff
@ -1,714 +0,0 @@
|
||||
/*
|
||||
* $Id: ld.h,v 1.19 1996/02/22 00:19:57 pk Exp $
|
||||
*/
|
||||
/*-
|
||||
* This code is derived from software copyrighted by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
|
||||
*/
|
||||
|
||||
#define SUN_COMPAT
|
||||
|
||||
#ifndef N_SIZE
|
||||
#define N_SIZE 0xc
|
||||
#endif
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef __P
|
||||
#ifndef __STDC__
|
||||
#define __P(a) ()
|
||||
#else
|
||||
#define __P(a) a
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* If compiled with GNU C, use the built-in alloca */
|
||||
#if defined(__GNUC__) || defined(sparc)
|
||||
#define alloca __builtin_alloca
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#define FreeBSD
|
||||
#endif
|
||||
|
||||
#include "md.h"
|
||||
#include "link.h"
|
||||
|
||||
/* Macro to control the number of undefined references printed */
|
||||
#define MAX_UREFS_PRINTED 10
|
||||
|
||||
/* Align to power-of-two boundary */
|
||||
#define PALIGN(x,p) (((x) + (u_long)(p) - 1) & (-(u_long)(p)))
|
||||
|
||||
/* Align to machine dependent boundary */
|
||||
#define MALIGN(x) PALIGN(x,MAX_ALIGNMENT)
|
||||
|
||||
/* Define this to specify the default executable format. */
|
||||
#ifndef DEFAULT_MAGIC
|
||||
#ifdef FreeBSD
|
||||
#define DEFAULT_MAGIC QMAGIC
|
||||
extern int netzmagic;
|
||||
#else
|
||||
#define DEFAULT_MAGIC ZMAGIC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Ok. Following are the relocation information macros. If your
|
||||
* system should not be able to use the default set (below), you must
|
||||
* define the following:
|
||||
|
||||
* relocation_info: This must be typedef'd (or #define'd) to the type
|
||||
* of structure that is stored in the relocation info section of your
|
||||
* a.out files. Often this is defined in the a.out.h for your system.
|
||||
*
|
||||
* RELOC_ADDRESS (rval): Offset into the current section of the
|
||||
* <whatever> to be relocated. *Must be an lvalue*.
|
||||
*
|
||||
* RELOC_EXTERN_P (rval): Is this relocation entry based on an
|
||||
* external symbol (1), or was it fully resolved upon entering the
|
||||
* loader (0) in which case some combination of the value in memory
|
||||
* (if RELOC_MEMORY_ADD_P) and the extra (if RELOC_ADD_EXTRA) contains
|
||||
* what the value of the relocation actually was. *Must be an lvalue*.
|
||||
*
|
||||
* RELOC_TYPE (rval): If this entry was fully resolved upon
|
||||
* entering the loader, what type should it be relocated as?
|
||||
*
|
||||
* RELOC_SYMBOL (rval): If this entry was not fully resolved upon
|
||||
* entering the loader, what is the index of it's symbol in the symbol
|
||||
* table? *Must be a lvalue*.
|
||||
*
|
||||
* RELOC_MEMORY_ADD_P (rval): This should return true if the final
|
||||
* relocation value output here should be added to memory, or if the
|
||||
* section of memory described should simply be set to the relocation
|
||||
* value.
|
||||
*
|
||||
* RELOC_ADD_EXTRA (rval): (Optional) This macro, if defined, gives
|
||||
* an extra value to be added to the relocation value based on the
|
||||
* individual relocation entry. *Must be an lvalue if defined*.
|
||||
*
|
||||
* RELOC_PCREL_P (rval): True if the relocation value described is
|
||||
* pc relative.
|
||||
*
|
||||
* RELOC_VALUE_RIGHTSHIFT (rval): Number of bits right to shift the
|
||||
* final relocation value before putting it where it belongs.
|
||||
*
|
||||
* RELOC_TARGET_SIZE (rval): log to the base 2 of the number of
|
||||
* bytes of size this relocation entry describes; 1 byte == 0; 2 bytes
|
||||
* == 1; 4 bytes == 2, and etc. This is somewhat redundant (we could
|
||||
* do everything in terms of the bit operators below), but having this
|
||||
* macro could end up producing better code on machines without fancy
|
||||
* bit twiddling. Also, it's easier to understand/code big/little
|
||||
* endian distinctions with this macro.
|
||||
*
|
||||
* RELOC_TARGET_BITPOS (rval): The starting bit position within the
|
||||
* object described in RELOC_TARGET_SIZE in which the relocation value
|
||||
* will go.
|
||||
*
|
||||
* RELOC_TARGET_BITSIZE (rval): How many bits are to be replaced
|
||||
* with the bits of the relocation value. It may be assumed by the
|
||||
* code that the relocation value will fit into this many bits. This
|
||||
* may be larger than RELOC_TARGET_SIZE if such be useful.
|
||||
*
|
||||
*
|
||||
* Things I haven't implemented
|
||||
* ----------------------------
|
||||
*
|
||||
* Values for RELOC_TARGET_SIZE other than 0, 1, or 2.
|
||||
*
|
||||
* Pc relative relocation for External references.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Default macros */
|
||||
#ifndef RELOC_ADDRESS
|
||||
|
||||
#define RELOC_ADDRESS(r) ((r)->r_address)
|
||||
#define RELOC_EXTERN_P(r) ((r)->r_extern)
|
||||
#define RELOC_TYPE(r) ((r)->r_symbolnum)
|
||||
#define RELOC_SYMBOL(r) ((r)->r_symbolnum)
|
||||
#define RELOC_MEMORY_SUB_P(r) 0
|
||||
#define RELOC_MEMORY_ADD_P(r) 1
|
||||
#undef RELOC_ADD_EXTRA
|
||||
#define RELOC_PCREL_P(r) ((r)->r_pcrel)
|
||||
#define RELOC_VALUE_RIGHTSHIFT(r) 0
|
||||
#if defined(RTLD) && defined(SUN_COMPAT)
|
||||
#define RELOC_TARGET_SIZE(r) (2) /* !!!!! Sun BUG compatible */
|
||||
#else
|
||||
#define RELOC_TARGET_SIZE(r) ((r)->r_length)
|
||||
#endif
|
||||
#define RELOC_TARGET_BITPOS(r) 0
|
||||
#define RELOC_TARGET_BITSIZE(r) 32
|
||||
|
||||
#define RELOC_JMPTAB_P(r) ((r)->r_jmptable)
|
||||
#define RELOC_BASEREL_P(r) ((r)->r_baserel)
|
||||
#define RELOC_RELATIVE_P(r) ((r)->r_relative)
|
||||
#define RELOC_COPY_P(r) ((r)->r_copy)
|
||||
#define RELOC_LAZY_P(r) ((r)->r_jmptable)
|
||||
|
||||
#define CHECK_GOT_RELOC(r) ((r)->r_pcrel)
|
||||
#define RELOC_PIC_TYPE(r) ((r)->r_baserel? \
|
||||
PIC_TYPE_LARGE:PIC_TYPE_NONE)
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef RELOC_INIT_SEGMENT_RELOC
|
||||
#define RELOC_INIT_SEGMENT_RELOC(r)
|
||||
#endif
|
||||
|
||||
#ifndef MAX_GOTOFF
|
||||
#define MAX_GOTOFF(x) (LONG_MAX)
|
||||
#endif
|
||||
|
||||
#ifndef MIN_GOTOFF
|
||||
#define MIN_GOTOFF(x) (LONG_MIN)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Internal representation of relocation types
|
||||
*/
|
||||
#define RELTYPE_EXTERN 1
|
||||
#define RELTYPE_JMPSLOT 2
|
||||
#define RELTYPE_BASEREL 4
|
||||
#define RELTYPE_RELATIVE 8
|
||||
#define RELTYPE_COPY 16
|
||||
|
||||
#ifdef nounderscore
|
||||
#define LPREFIX '.'
|
||||
#else
|
||||
#define LPREFIX 'L'
|
||||
#endif
|
||||
|
||||
#ifndef TEXT_START
|
||||
#define TEXT_START(x) N_TXTADDR(x)
|
||||
#endif
|
||||
|
||||
#ifndef DATA_START
|
||||
#define DATA_START(x) N_DATADDR(x)
|
||||
#endif
|
||||
|
||||
/* If a this type of symbol is encountered, its name is a warning
|
||||
message to print each time the symbol referenced by the next symbol
|
||||
table entry is referenced.
|
||||
|
||||
This feature may be used to allow backwards compatibility with
|
||||
certain functions (eg. gets) but to discourage programmers from
|
||||
their use.
|
||||
|
||||
So if, for example, you wanted to have ld print a warning whenever
|
||||
the function "gets" was used in their C program, you would add the
|
||||
following to the assembler file in which gets is defined:
|
||||
|
||||
.stabs "Obsolete function \"gets\" referenced",30,0,0,0
|
||||
.stabs "_gets",1,0,0,0
|
||||
|
||||
These .stabs do not necessarily have to be in the same file as the
|
||||
gets function, they simply must exist somewhere in the compilation. */
|
||||
|
||||
#ifndef N_WARNING
|
||||
#define N_WARNING 0x1E /* Warning message to print if symbol
|
||||
included */
|
||||
#endif /* This is input to ld */
|
||||
|
||||
/* Special global symbol types understood by GNU LD. */
|
||||
|
||||
/* The following type indicates the definition of a symbol as being
|
||||
an indirect reference to another symbol. The other symbol
|
||||
appears as an undefined reference, immediately following this symbol.
|
||||
|
||||
Indirection is asymmetrical. The other symbol's value will be used
|
||||
to satisfy requests for the indirect symbol, but not vice versa.
|
||||
If the other symbol does not have a definition, libraries will
|
||||
be searched to find a definition.
|
||||
|
||||
So, for example, the following two lines placed in an assembler
|
||||
input file would result in an object file which would direct gnu ld
|
||||
to resolve all references to symbol "foo" as references to symbol
|
||||
"bar".
|
||||
|
||||
.stabs "_foo",11,0,0,0
|
||||
.stabs "_bar",1,0,0,0
|
||||
|
||||
Note that (11 == (N_INDR | N_EXT)) and (1 == (N_UNDF | N_EXT)). */
|
||||
|
||||
#ifndef N_INDR
|
||||
#define N_INDR 0xa
|
||||
#endif
|
||||
|
||||
/* The following symbols refer to set elements. These are expected
|
||||
only in input to the loader; they should not appear in loader
|
||||
output (unless relocatable output is requested). To be recognized
|
||||
by the loader, the input symbols must have their N_EXT bit set.
|
||||
All the N_SET[ATDB] symbols with the same name form one set. The
|
||||
loader collects all of these elements at load time and outputs a
|
||||
vector for each name.
|
||||
Space (an array of 32 bit words) is allocated for the set in the
|
||||
data section, and the n_value field of each set element value is
|
||||
stored into one word of the array.
|
||||
The first word of the array is the length of the set (number of
|
||||
elements). The last word of the vector is set to zero for possible
|
||||
use by incremental loaders. The array is ordered by the linkage
|
||||
order; the first symbols which the linker encounters will be first
|
||||
in the array.
|
||||
|
||||
In C syntax this looks like:
|
||||
|
||||
struct set_vector {
|
||||
unsigned int length;
|
||||
unsigned int vector[length];
|
||||
unsigned int always_zero;
|
||||
};
|
||||
|
||||
Before being placed into the array, each element is relocated
|
||||
according to its type. This allows the loader to create an array
|
||||
of pointers to objects automatically. N_SETA type symbols will not
|
||||
be relocated.
|
||||
|
||||
The address of the set is made into an N_SETV symbol
|
||||
whose name is the same as the name of the set.
|
||||
This symbol acts like a N_DATA global symbol
|
||||
in that it can satisfy undefined external references.
|
||||
|
||||
For the purposes of determining whether or not to load in a library
|
||||
file, set element definitions are not considered "real
|
||||
definitions"; they will not cause the loading of a library
|
||||
member.
|
||||
|
||||
If relocatable output is requested, none of this processing is
|
||||
done. The symbols are simply relocated and passed through to the
|
||||
output file.
|
||||
|
||||
So, for example, the following three lines of assembler code
|
||||
(whether in one file or scattered between several different ones)
|
||||
will produce a three element vector (total length is five words;
|
||||
see above), referenced by the symbol "_xyzzy", which will have the
|
||||
addresses of the routines _init1, _init2, and _init3.
|
||||
|
||||
*NOTE*: If symbolic addresses are used in the n_value field of the
|
||||
defining .stabs, those symbols must be defined in the same file as
|
||||
that containing the .stabs.
|
||||
|
||||
.stabs "_xyzzy",23,0,0,_init1
|
||||
.stabs "_xyzzy",23,0,0,_init2
|
||||
.stabs "_xyzzy",23,0,0,_init3
|
||||
|
||||
Note that (23 == (N_SETT | N_EXT)). */
|
||||
|
||||
#ifndef N_SETA
|
||||
#define N_SETA 0x14 /* Absolute set element symbol */
|
||||
#endif /* This is input to LD, in a .o file. */
|
||||
|
||||
#ifndef N_SETT
|
||||
#define N_SETT 0x16 /* Text set element symbol */
|
||||
#endif /* This is input to LD, in a .o file. */
|
||||
|
||||
#ifndef N_SETD
|
||||
#define N_SETD 0x18 /* Data set element symbol */
|
||||
#endif /* This is input to LD, in a .o file. */
|
||||
|
||||
#ifndef N_SETB
|
||||
#define N_SETB 0x1A /* Bss set element symbol */
|
||||
#endif /* This is input to LD, in a .o file. */
|
||||
|
||||
/* Macros dealing with the set element symbols defined in a.out.h */
|
||||
#define SET_ELEMENT_P(x) ((x) >= N_SETA && (x) <= (N_SETB|N_EXT))
|
||||
#define TYPE_OF_SET_ELEMENT(x) ((x) - N_SETA + N_ABS)
|
||||
|
||||
#ifndef N_SETV
|
||||
#define N_SETV 0x1C /* Pointer to set vector in data area. */
|
||||
#endif /* This is output from LD. */
|
||||
|
||||
|
||||
#ifndef __GNU_STAB__
|
||||
/* Line number for the data section. This is to be used to describe
|
||||
the source location of a variable declaration. */
|
||||
#ifndef N_DSLINE
|
||||
#define N_DSLINE (N_SLINE+N_DATA-N_TEXT)
|
||||
#endif
|
||||
|
||||
/* Line number for the bss section. This is to be used to describe
|
||||
the source location of a variable declaration. */
|
||||
#ifndef N_BSLINE
|
||||
#define N_BSLINE (N_SLINE+N_BSS-N_TEXT)
|
||||
#endif
|
||||
#endif /* not __GNU_STAB__ */
|
||||
|
||||
#define N_ISWEAK(p) (N_BIND(p) & BIND_WEAK)
|
||||
|
||||
|
||||
typedef struct localsymbol {
|
||||
struct nzlist nzlist; /* n[z]list from file */
|
||||
struct glosym *symbol; /* Corresponding global symbol,
|
||||
if any */
|
||||
struct localsymbol *next; /* List of definitions */
|
||||
struct file_entry *entry; /* Backpointer to file */
|
||||
long gotslot_offset; /* Position in GOT, if any */
|
||||
int symbolnum; /* Position in output nlist */
|
||||
int flags;
|
||||
#define LS_L_SYMBOL 1 /* Local symbol starts with an `L' */
|
||||
#define LS_WRITE 2 /* Symbol goes in output symtable */
|
||||
#define LS_RENAME 4 /* xlat name to `<file>.<name>' */
|
||||
#define LS_HASGOTSLOT 8 /* This symbol has a GOT entry */
|
||||
#define LS_WARNING 16 /* Second part of a N_WARNING duo */
|
||||
} localsymbol_t;
|
||||
|
||||
/* Symbol table */
|
||||
|
||||
/*
|
||||
* Global symbol data is recorded in these structures, one for each global
|
||||
* symbol. They are found via hashing in 'symtab', which points to a vector
|
||||
* of buckets. Each bucket is a chain of these structures through the link
|
||||
* field.
|
||||
*/
|
||||
|
||||
typedef struct glosym {
|
||||
struct glosym *link; /* Next symbol hash bucket. */
|
||||
char *name; /* Name of this symbol. */
|
||||
long value; /* Value of this symbol */
|
||||
localsymbol_t *refs; /* Chain of local symbols from object
|
||||
files pertaining to this global
|
||||
symbol */
|
||||
localsymbol_t *sorefs;/* Same for local symbols from shared
|
||||
object files. */
|
||||
|
||||
char *warning; /* message, from N_WARNING nlists */
|
||||
int common_size; /* Common size */
|
||||
int symbolnum; /* Symbol index in output symbol table */
|
||||
int rrs_symbolnum; /* Symbol index in RRS symbol table */
|
||||
|
||||
localsymbol_t *def_lsp; /* The local symbol that gave this
|
||||
global symbol its definition */
|
||||
|
||||
char defined; /* Definition of this symbol */
|
||||
char so_defined; /* Definition of this symbol in a shared
|
||||
object. These go into the RRS symbol table */
|
||||
u_char undef_refs; /* Count of number of "undefined"
|
||||
messages printed for this symbol */
|
||||
u_char mult_defs; /* Same for "multiply defined" symbols */
|
||||
struct glosym *alias; /* For symbols of type N_INDR, this
|
||||
points at the real symbol. */
|
||||
int setv_count; /* Number of elements in N_SETV symbols */
|
||||
int size; /* Size of this symbol (either from N_SIZE
|
||||
symbols or a from shared object's RRS */
|
||||
int aux; /* Auxiliary type information conveyed in
|
||||
the `n_other' field of nlists */
|
||||
|
||||
/* The offset into one of the RRS tables, -1 if not used */
|
||||
long jmpslot_offset;
|
||||
long gotslot_offset;
|
||||
|
||||
long flags;
|
||||
|
||||
#define GS_DEFINED 0x1 /* Symbol has definition (notyetused)*/
|
||||
#define GS_REFERENCED 0x2 /* Symbol is referred to by something
|
||||
interesting */
|
||||
#define GS_TRACE 0x4 /* Symbol will be traced */
|
||||
#define GS_HASJMPSLOT 0x8 /* */
|
||||
#define GS_HASGOTSLOT 0x10 /* Some state bits concerning */
|
||||
#define GS_CPYRELOCRESERVED 0x20 /* entries in GOT and PLT tables */
|
||||
#define GS_CPYRELOCCLAIMED 0x40 /* */
|
||||
#define GS_WEAK 0x80 /* Symbol is weakly defined */
|
||||
|
||||
} symbol;
|
||||
|
||||
/* Number of buckets in symbol hash table */
|
||||
#define SYMTABSIZE 1009
|
||||
|
||||
/* The symbol hash table: a vector of SYMTABSIZE pointers to struct glosym. */
|
||||
extern symbol *symtab[];
|
||||
#define FOR_EACH_SYMBOL(i,sp) { \
|
||||
int i; \
|
||||
for (i = 0; i < SYMTABSIZE; i++) { \
|
||||
register symbol *sp; \
|
||||
for (sp = symtab[i]; sp; sp = sp->link)
|
||||
|
||||
#define END_EACH_SYMBOL }}
|
||||
|
||||
/* # of global symbols referenced and not defined. */
|
||||
extern int undefined_global_sym_count;
|
||||
|
||||
/* # of weak symbols referenced and not defined. */
|
||||
extern int undefined_weak_sym_count;
|
||||
|
||||
/* # of undefined symbols referenced by shared objects */
|
||||
extern int undefined_shobj_sym_count;
|
||||
|
||||
/* # of multiply defined symbols. */
|
||||
extern int multiple_def_count;
|
||||
|
||||
/* # of common symbols. */
|
||||
extern int common_defined_global_count;
|
||||
|
||||
/* # of warning symbols encountered. */
|
||||
extern int warn_sym_count;
|
||||
extern int list_warning_symbols;
|
||||
|
||||
/*
|
||||
* Define a linked list of strings which define symbols which should be
|
||||
* treated as set elements even though they aren't. Any symbol with a prefix
|
||||
* matching one of these should be treated as a set element.
|
||||
*
|
||||
* This is to make up for deficiencies in many assemblers which aren't willing
|
||||
* to pass any stabs through to the loader which they don't understand.
|
||||
*/
|
||||
struct string_list_element {
|
||||
char *str;
|
||||
struct string_list_element *next;
|
||||
};
|
||||
|
||||
extern symbol *entry_symbol; /* the entry symbol, if any */
|
||||
extern symbol *edata_symbol; /* the symbol _edata */
|
||||
extern symbol *etext_symbol; /* the symbol _etext */
|
||||
extern symbol *end_symbol; /* the symbol _end */
|
||||
extern symbol *got_symbol; /* the symbol __GLOBAL_OFFSET_TABLE_ */
|
||||
extern symbol *dynamic_symbol; /* the symbol __DYNAMIC */
|
||||
|
||||
/*
|
||||
* Each input file, and each library member ("subfile") being loaded, has a
|
||||
* `file_entry' structure for it.
|
||||
*
|
||||
* For files specified by command args, these are contained in the vector which
|
||||
* `file_table' points to.
|
||||
*
|
||||
* For library members, they are dynamically allocated, and chained through the
|
||||
* `chain' field. The chain is found in the `subfiles' field of the
|
||||
* `file_entry'. The `file_entry' objects for the members have `superfile'
|
||||
* fields pointing to the one for the library.
|
||||
*/
|
||||
|
||||
struct file_entry {
|
||||
char *filename; /* Name of this file. */
|
||||
/*
|
||||
* Name to use for the symbol giving address of text start Usually
|
||||
* the same as filename, but for a file spec'd with -l this is the -l
|
||||
* switch itself rather than the filename.
|
||||
*/
|
||||
char *local_sym_name;
|
||||
struct exec header; /* The file's a.out header. */
|
||||
localsymbol_t *symbols; /* Symbol table of the file. */
|
||||
int nsymbols; /* Number of symbols in above array. */
|
||||
int string_size; /* Size in bytes of string table. */
|
||||
char *strings; /* Pointer to the string table when
|
||||
in core, NULL otherwise */
|
||||
int strings_offset; /* Offset of string table,
|
||||
(normally N_STROFF() + 4) */
|
||||
/*
|
||||
* Next two used only if `relocatable_output' or if needed for
|
||||
* output of undefined reference line numbers.
|
||||
*/
|
||||
struct relocation_info *textrel; /* Text relocations */
|
||||
int ntextrel; /* # of text relocations */
|
||||
struct relocation_info *datarel; /* Data relocations */
|
||||
int ndatarel; /* # of data relocations */
|
||||
|
||||
/*
|
||||
* Relation of this file's segments to the output file.
|
||||
*/
|
||||
int text_start_address; /* Start of this file's text segment
|
||||
in the output file core image. */
|
||||
int data_start_address; /* Start of this file's data segment
|
||||
in the output file core image. */
|
||||
int bss_start_address; /* Start of this file's bss segment
|
||||
in the output file core image. */
|
||||
struct file_entry *subfiles; /* For a library, points to chain of
|
||||
entries for the library members. */
|
||||
struct file_entry *superfile; /* For library member, points to the
|
||||
library's own entry. */
|
||||
struct file_entry *chain; /* For library member, points to next
|
||||
entry for next member. */
|
||||
int starting_offset; /* For a library member, offset of the
|
||||
member within the archive. Zero for
|
||||
files that are not library members.*/
|
||||
int total_size; /* Size of contents of this file,
|
||||
if library member. */
|
||||
#ifdef SUN_COMPAT
|
||||
struct file_entry *silly_archive;/* For shared libraries which have
|
||||
a .sa companion */
|
||||
#endif
|
||||
int lib_major, lib_minor; /* Version numbers of a shared object */
|
||||
|
||||
int flags;
|
||||
#define E_IS_LIBRARY 1 /* File is a an archive */
|
||||
#define E_HEADER_VALID 2 /* File's header has been read */
|
||||
#define E_SEARCH_DIRS 4 /* Search directories for file */
|
||||
#define E_SEARCH_DYNAMIC 8 /* Search for shared libs allowed */
|
||||
#define E_JUST_SYMS 0x10 /* File is used for incremental load */
|
||||
#define E_DYNAMIC 0x20 /* File is a shared object */
|
||||
#define E_SCRAPPED 0x40 /* Ignore this file */
|
||||
#define E_SYMBOLS_USED 0x80 /* Symbols from this entry were used */
|
||||
#define E_SECONDCLASS 0x100 /* Shared object is a subsidiary */
|
||||
};
|
||||
|
||||
/*
|
||||
* Section start addresses.
|
||||
*/
|
||||
extern int text_size; /* total size of text. */
|
||||
extern int text_start; /* start of text */
|
||||
extern int text_pad; /* clear space between text and data */
|
||||
extern int data_size; /* total size of data. */
|
||||
extern int data_start; /* start of data */
|
||||
extern int data_pad; /* part of bss segment within data */
|
||||
|
||||
extern int bss_size; /* total size of bss. */
|
||||
extern int bss_start; /* start of bss */
|
||||
|
||||
extern int text_reloc_size; /* total size of text relocation. */
|
||||
extern int data_reloc_size; /* total size of data relocation. */
|
||||
|
||||
/*
|
||||
* Runtime Relocation Section (RRS).
|
||||
* This describes the data structures that go into the output text and data
|
||||
* segments to support the run-time linker. The RRS can be empty (plain old
|
||||
* static linking), or can just exist of GOT and PLT entries (in case of
|
||||
* statically linked PIC code).
|
||||
*/
|
||||
extern int rrs_section_type; /* What's in the RRS section */
|
||||
#define RRS_NONE 0
|
||||
#define RRS_PARTIAL 1
|
||||
#define RRS_FULL 2
|
||||
extern int rrs_text_size; /* Size of RRS text additions */
|
||||
extern int rrs_text_start; /* Location of above */
|
||||
extern int rrs_data_size; /* Size of RRS data additions */
|
||||
extern int rrs_data_start; /* Location of above */
|
||||
extern char *rrs_search_paths; /* `-L' RT paths */
|
||||
|
||||
/* Version number to put in __DYNAMIC (set by -V) */
|
||||
extern int soversion;
|
||||
#ifndef DEFAULT_SOVERSION
|
||||
#define DEFAULT_SOVERSION LD_VERSION_BSD
|
||||
#endif
|
||||
|
||||
extern int pc_relocation; /* Current PC reloc value */
|
||||
|
||||
extern int number_of_shobjs; /* # of shared objects linked in */
|
||||
|
||||
/* Current link mode */
|
||||
extern int link_mode;
|
||||
#define DYNAMIC 1 /* Consider shared libraries */
|
||||
#define SYMBOLIC 2 /* Force symbolic resolution */
|
||||
#define FORCEARCHIVE 4 /* Force inclusion of all members
|
||||
of archives */
|
||||
#define SHAREABLE 8 /* Build a shared object */
|
||||
#define SILLYARCHIVE 16 /* Process .sa companions, if any */
|
||||
|
||||
extern FILE *outstream; /* Output file. */
|
||||
extern struct exec outheader; /* Output file header. */
|
||||
extern int magic; /* Output file magic. */
|
||||
extern int oldmagic;
|
||||
extern int relocatable_output;
|
||||
extern int pic_type;
|
||||
#define PIC_TYPE_NONE 0
|
||||
#define PIC_TYPE_SMALL 1
|
||||
#define PIC_TYPE_LARGE 2
|
||||
|
||||
/* Size of a page. */
|
||||
extern int page_size;
|
||||
|
||||
extern char **search_dirs; /* Directories to search for libraries. */
|
||||
extern int n_search_dirs; /* Length of above. */
|
||||
|
||||
extern int write_map; /* write a load map (`-M') */
|
||||
|
||||
void read_header __P((int, struct file_entry *));
|
||||
void read_entry_symbols __P((int, struct file_entry *));
|
||||
void read_entry_strings __P((int, struct file_entry *));
|
||||
void read_entry_relocation __P((int, struct file_entry *));
|
||||
void enter_file_symbols __P((struct file_entry *));
|
||||
void read_file_symbols __P((struct file_entry *));
|
||||
int set_element_prefixed_p __P((char *));
|
||||
int text_offset __P((struct file_entry *));
|
||||
int file_open __P((struct file_entry *));
|
||||
void each_file __P((void (*)(), void *));
|
||||
void each_full_file __P((void (*)(), void *));
|
||||
unsigned long check_each_file __P((unsigned long (*)(), void *));
|
||||
void mywrite __P((void *, int, int, FILE *));
|
||||
void padfile __P((int, FILE *));
|
||||
|
||||
/* In warnings.c: */
|
||||
void perror_name __P((char *));
|
||||
void perror_file __P((struct file_entry *));
|
||||
void print_symbols __P((FILE *));
|
||||
char *get_file_name __P((struct file_entry *));
|
||||
void print_file_name __P((struct file_entry *, FILE *));
|
||||
void prline_file_name __P((struct file_entry *, FILE *));
|
||||
int do_warnings __P((FILE *));
|
||||
|
||||
/* In etc.c: */
|
||||
void *xmalloc __P((size_t));
|
||||
void *xrealloc __P((void *, size_t));
|
||||
char *concat __P((const char *, const char *, const char *));
|
||||
|
||||
/* In symbol.c: */
|
||||
void symtab_init __P((int));
|
||||
symbol *getsym __P((char *)), *getsym_soft __P((char *));
|
||||
|
||||
/* In lib.c: */
|
||||
void search_library __P((int, struct file_entry *));
|
||||
void read_shared_object __P((int, struct file_entry *));
|
||||
int findlib __P((struct file_entry *));
|
||||
|
||||
/* In shlib.c: */
|
||||
char *findshlib __P((char *, int *, int *, int));
|
||||
void add_search_dir __P((char *));
|
||||
void add_search_path __P((char *));
|
||||
void std_search_path __P((void));
|
||||
int getdewey __P((int[], char *));
|
||||
int cmpndewey __P((int[], int, int[], int));
|
||||
|
||||
/* In rrs.c: */
|
||||
void init_rrs __P((void));
|
||||
int rrs_add_shobj __P((struct file_entry *));
|
||||
void alloc_rrs_reloc __P((struct file_entry *, symbol *));
|
||||
void alloc_rrs_segment_reloc __P((struct file_entry *, struct relocation_info *));
|
||||
void alloc_rrs_jmpslot __P((struct file_entry *, symbol *));
|
||||
void alloc_rrs_gotslot __P((struct file_entry *, struct relocation_info *, localsymbol_t *));
|
||||
void alloc_rrs_cpy_reloc __P((struct file_entry *, symbol *));
|
||||
|
||||
int claim_rrs_reloc __P((struct file_entry *, struct relocation_info *, symbol *, long *));
|
||||
long claim_rrs_jmpslot __P((struct file_entry *, struct relocation_info *, symbol *, long));
|
||||
long claim_rrs_gotslot __P((struct file_entry *, struct relocation_info *, struct localsymbol *, long));
|
||||
long claim_rrs_internal_gotslot __P((struct file_entry *, struct relocation_info *, struct localsymbol *, long));
|
||||
void claim_rrs_cpy_reloc __P((struct file_entry *, struct relocation_info *, symbol *));
|
||||
void claim_rrs_segment_reloc __P((struct file_entry *, struct relocation_info *));
|
||||
void consider_rrs_section_lengths __P((void));
|
||||
void relocate_rrs_addresses __P((void));
|
||||
void write_rrs __P((void));
|
||||
|
||||
/* In <md>.c */
|
||||
void md_init_header __P((struct exec *, int, int));
|
||||
long md_get_addend __P((struct relocation_info *, unsigned char *));
|
||||
void md_relocate __P((struct relocation_info *, long, unsigned char *, int));
|
||||
void md_make_jmpslot __P((jmpslot_t *, long, long));
|
||||
void md_fix_jmpslot __P((jmpslot_t *, long, u_long));
|
||||
int md_make_reloc __P((struct relocation_info *, struct relocation_info *, int));
|
||||
void md_make_jmpreloc __P((struct relocation_info *, struct relocation_info *, int));
|
||||
void md_make_gotreloc __P((struct relocation_info *, struct relocation_info *, int));
|
||||
void md_make_copyreloc __P((struct relocation_info *, struct relocation_info *));
|
||||
void md_set_breakpoint __P((long, long *));
|
||||
|
||||
#ifdef NEED_SWAP
|
||||
void md_swapin_exec_hdr __P((struct exec *));
|
||||
void md_swapout_exec_hdr __P((struct exec *));
|
||||
void md_swapin_reloc __P((struct relocation_info *, int));
|
||||
void md_swapout_reloc __P((struct relocation_info *, int));
|
||||
void md_swapout_jmpslot __P((jmpslot_t *, int));
|
||||
|
||||
/* In xbits.c: */
|
||||
void swap_longs __P((long *, int));
|
||||
void swap_symbols __P((struct nlist *, int));
|
||||
void swap_zsymbols __P((struct nzlist *, int));
|
||||
void swap_ranlib_hdr __P((struct ranlib *, int));
|
||||
void swap__dynamic __P((struct link_dynamic *));
|
||||
void swap_section_dispatch_table __P((struct section_dispatch_table *));
|
||||
void swap_so_debug __P((struct so_debug *));
|
||||
void swapin_sod __P((struct sod *, int));
|
||||
void swapout_sod __P((struct sod *, int));
|
||||
void swapout_fshash __P((struct fshash *, int));
|
||||
#endif
|
8
gnu/usr.bin/ld/ld/Makefile
Normal file
8
gnu/usr.bin/ld/ld/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $NetBSD: Makefile,v 1.1 1997/04/16 16:49:41 christos Exp $
|
||||
|
||||
PROG= ld
|
||||
SRCS= ld.c symbol.c lib.c shlib.c warnings.c etc.c rrs.c xbits.c md.c
|
||||
LDADD+= -lgnumalloc
|
||||
DPADD+= /usr/lib/libgnumalloc.a
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,13 +1,9 @@
|
||||
# $NetBSD: Makefile,v 1.10 1995/03/06 04:24:41 cgd Exp $
|
||||
# $NetBSD: Makefile,v 1.11 1997/04/16 16:49:42 christos Exp $
|
||||
|
||||
PROG= ldconfig
|
||||
SRCS= ldconfig.c shlib.c etc.c
|
||||
LDDIR?= $(.CURDIR)/..
|
||||
CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE_ARCH)
|
||||
LDSTATIC=-static
|
||||
BINDIR= /sbin
|
||||
MAN= ldconfig.8
|
||||
|
||||
.PATH: $(LDDIR) $(LDDIR)/$(MACHINE_ARCH)
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1,846 +0,0 @@
|
||||
/*
|
||||
* $Id: lib.c,v 1.16 1995/06/04 21:33:14 pk Exp $ - library routines
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <ar.h>
|
||||
#include <ranlib.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
static void linear_library __P((int, struct file_entry *));
|
||||
static void symdef_library __P((int, struct file_entry *, int));
|
||||
static struct file_entry *decode_library_subfile __P((int,
|
||||
struct file_entry *,
|
||||
int, int *));
|
||||
|
||||
/*
|
||||
* Search the library ENTRY, already open on descriptor FD. This means
|
||||
* deciding which library members to load, making a chain of `struct
|
||||
* file_entry' for those members, and entering their global symbols in the
|
||||
* hash table.
|
||||
*/
|
||||
|
||||
void
|
||||
search_library(fd, entry)
|
||||
int fd;
|
||||
struct file_entry *entry;
|
||||
{
|
||||
int member_length;
|
||||
register char *name;
|
||||
register struct file_entry *subentry;
|
||||
|
||||
if (!(link_mode & FORCEARCHIVE) && !undefined_global_sym_count)
|
||||
return;
|
||||
|
||||
/* Examine its first member, which starts SARMAG bytes in. */
|
||||
subentry = decode_library_subfile(fd, entry, SARMAG, &member_length);
|
||||
if (!subentry)
|
||||
return;
|
||||
|
||||
name = subentry->filename;
|
||||
free(subentry);
|
||||
|
||||
/* Search via __.SYMDEF if that exists, else linearly. */
|
||||
|
||||
if (!strcmp(name, "__.SYMDEF"))
|
||||
symdef_library(fd, entry, member_length);
|
||||
else
|
||||
linear_library(fd, entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct and return a file_entry for a library member. The library's
|
||||
* file_entry is library_entry, and the library is open on FD.
|
||||
* SUBFILE_OFFSET is the byte index in the library of this member's header.
|
||||
* We store the length of the member into *LENGTH_LOC.
|
||||
*/
|
||||
|
||||
static struct file_entry *
|
||||
decode_library_subfile(fd, library_entry, subfile_offset, length_loc)
|
||||
int fd;
|
||||
struct file_entry *library_entry;
|
||||
int subfile_offset;
|
||||
int *length_loc;
|
||||
{
|
||||
int bytes_read;
|
||||
register int namelen;
|
||||
int member_length, content_length;
|
||||
int starting_offset;
|
||||
register char *name;
|
||||
struct ar_hdr hdr1;
|
||||
register struct file_entry *subentry;
|
||||
|
||||
lseek(fd, subfile_offset, 0);
|
||||
|
||||
bytes_read = read(fd, &hdr1, sizeof hdr1);
|
||||
if (!bytes_read)
|
||||
return 0; /* end of archive */
|
||||
|
||||
if (sizeof hdr1 != bytes_read)
|
||||
errx(1, "%s: malformed library archive",
|
||||
get_file_name(library_entry));
|
||||
|
||||
if (sscanf(hdr1.ar_size, "%d", &member_length) != 1)
|
||||
errx(1, "%s: malformatted header of archive member: %.*s",
|
||||
get_file_name(library_entry),
|
||||
sizeof(hdr1.ar_name), hdr1.ar_name);
|
||||
|
||||
subentry = (struct file_entry *) xmalloc(sizeof(struct file_entry));
|
||||
bzero(subentry, sizeof(struct file_entry));
|
||||
|
||||
for (namelen = 0;
|
||||
namelen < sizeof hdr1.ar_name
|
||||
&& hdr1.ar_name[namelen] != 0 && hdr1.ar_name[namelen] != ' '
|
||||
&& hdr1.ar_name[namelen] != '/';
|
||||
namelen++);
|
||||
|
||||
starting_offset = subfile_offset + sizeof hdr1;
|
||||
content_length = member_length;
|
||||
|
||||
#ifdef AR_EFMT1
|
||||
/*
|
||||
* BSD 4.4 extended AR format: #1/<namelen>, with name as the
|
||||
* first <namelen> bytes of the file
|
||||
*/
|
||||
if (strncmp(hdr1.ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 &&
|
||||
isdigit(hdr1.ar_name[sizeof(AR_EFMT1) - 1])) {
|
||||
|
||||
namelen = atoi(&hdr1.ar_name[sizeof(AR_EFMT1) - 1]);
|
||||
name = (char *)xmalloc(namelen + 1);
|
||||
if (read(fd, name, namelen) != namelen)
|
||||
errx(1, "%s: malformatted archive member: %.*s",
|
||||
get_file_name(library_entry),
|
||||
sizeof(hdr1.ar_name), hdr1.ar_name);
|
||||
name[namelen] = 0;
|
||||
content_length -= namelen;
|
||||
starting_offset += namelen;
|
||||
} else
|
||||
|
||||
#endif
|
||||
{
|
||||
name = (char *)xmalloc(namelen + 1);
|
||||
strncpy(name, hdr1.ar_name, namelen);
|
||||
name[namelen] = 0;
|
||||
}
|
||||
|
||||
subentry->filename = name;
|
||||
subentry->local_sym_name = name;
|
||||
subentry->starting_offset = starting_offset;
|
||||
subentry->superfile = library_entry;
|
||||
subentry->total_size = content_length;
|
||||
#if 0
|
||||
subentry->symbols = 0;
|
||||
subentry->strings = 0;
|
||||
subentry->subfiles = 0;
|
||||
subentry->chain = 0;
|
||||
subentry->flags = 0;
|
||||
#endif
|
||||
|
||||
(*length_loc) = member_length;
|
||||
|
||||
return subentry;
|
||||
}
|
||||
|
||||
static int subfile_wanted_p __P((struct file_entry *));
|
||||
|
||||
/*
|
||||
* Search a library that has a __.SYMDEF member. FD is a descriptor on
|
||||
* which the library is open. The file pointer is assumed to point at the
|
||||
* __.SYMDEF data. ENTRY is the library's file_entry. MEMBER_LENGTH is the
|
||||
* length of the __.SYMDEF data.
|
||||
*/
|
||||
|
||||
static void
|
||||
symdef_library(fd, entry, member_length)
|
||||
int fd;
|
||||
struct file_entry *entry;
|
||||
int member_length;
|
||||
{
|
||||
int *symdef_data = (int *) xmalloc(member_length);
|
||||
register struct ranlib *symdef_base;
|
||||
char *sym_name_base;
|
||||
int nsymdefs;
|
||||
int length_of_strings;
|
||||
int not_finished;
|
||||
int bytes_read;
|
||||
register int i;
|
||||
struct file_entry *prev = 0;
|
||||
int prev_offset = 0;
|
||||
|
||||
bytes_read = read(fd, symdef_data, member_length);
|
||||
if (bytes_read != member_length)
|
||||
errx(1, "%s: malformatted __.SYMDEF",
|
||||
get_file_name(entry));
|
||||
|
||||
nsymdefs = md_swap_long(*symdef_data) / sizeof(struct ranlib);
|
||||
if (nsymdefs < 0 ||
|
||||
nsymdefs * sizeof(struct ranlib) + 2 * sizeof(int) > member_length)
|
||||
errx(1, "%s: malformatted __.SYMDEF",
|
||||
get_file_name(entry));
|
||||
|
||||
symdef_base = (struct ranlib *) (symdef_data + 1);
|
||||
length_of_strings = md_swap_long(*(int *) (symdef_base + nsymdefs));
|
||||
|
||||
if (length_of_strings < 0
|
||||
|| nsymdefs * sizeof(struct ranlib) + length_of_strings
|
||||
+ 2 * sizeof(int) > member_length)
|
||||
errx(1, "%s: malformatted __.SYMDEF",
|
||||
get_file_name(entry));
|
||||
|
||||
sym_name_base = sizeof(int) + (char *) (symdef_base + nsymdefs);
|
||||
|
||||
/* Check all the string indexes for validity. */
|
||||
md_swapin_ranlib_hdr(symdef_base, nsymdefs);
|
||||
for (i = 0; i < nsymdefs; i++) {
|
||||
register int index = symdef_base[i].ran_un.ran_strx;
|
||||
if (index < 0 || index >= length_of_strings
|
||||
|| (index && *(sym_name_base + index - 1)))
|
||||
errx(1, "%s: malformatted __.SYMDEF",
|
||||
get_file_name(entry));
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the symdef data for members to load. Do this until one
|
||||
* whole pass finds nothing to load.
|
||||
*/
|
||||
|
||||
not_finished = 1;
|
||||
while (not_finished) {
|
||||
|
||||
not_finished = 0;
|
||||
|
||||
/*
|
||||
* Scan all the symbols mentioned in the symdef for ones that
|
||||
* we need. Load the library members that contain such
|
||||
* symbols.
|
||||
*/
|
||||
|
||||
for (i = 0; (i < nsymdefs &&
|
||||
((link_mode & FORCEARCHIVE) ||
|
||||
undefined_global_sym_count ||
|
||||
common_defined_global_count)); i++) {
|
||||
|
||||
register symbol *sp;
|
||||
int junk;
|
||||
register int j;
|
||||
register int offset = symdef_base[i].ran_off;
|
||||
struct file_entry *subentry;
|
||||
|
||||
|
||||
if (symdef_base[i].ran_un.ran_strx < 0)
|
||||
continue;
|
||||
|
||||
sp = getsym_soft(sym_name_base
|
||||
+ symdef_base[i].ran_un.ran_strx);
|
||||
|
||||
/*
|
||||
* If we find a symbol that appears to be needed,
|
||||
* think carefully about the archive member that the
|
||||
* symbol is in.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Per Mike Karels' recommendation, we no longer load
|
||||
* library files if the only reference(s) that would
|
||||
* be satisfied are 'common' references. This
|
||||
* prevents some problems with name pollution (e.g. a
|
||||
* global common 'utime' linked to a function).
|
||||
*
|
||||
* If we're not forcing the archive in then we don't
|
||||
* need to bother if: we've never heard of the symbol,
|
||||
* or if it is already defined. The last clause causes
|
||||
* archive members to be searched for definitions
|
||||
* satisfying undefined shared object symbols.
|
||||
*/
|
||||
if (!(link_mode & FORCEARCHIVE) &&
|
||||
(!sp || sp->defined ||
|
||||
(!(sp->flags & GS_REFERENCED) &&
|
||||
!sp->sorefs)))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Don't think carefully about any archive member
|
||||
* more than once in a given pass.
|
||||
*/
|
||||
|
||||
if (prev_offset == offset)
|
||||
continue;
|
||||
prev_offset = offset;
|
||||
|
||||
/*
|
||||
* Read the symbol table of the archive member.
|
||||
*/
|
||||
|
||||
subentry = decode_library_subfile(fd,
|
||||
entry, offset, &junk);
|
||||
if (subentry == 0)
|
||||
errx(1,
|
||||
"invalid offset for %s in symbol table of %s",
|
||||
sym_name_base
|
||||
+ symdef_base[i].ran_un.ran_strx,
|
||||
entry->filename);
|
||||
|
||||
read_entry_symbols(fd, subentry);
|
||||
subentry->strings = (char *)
|
||||
alloca(subentry->string_size);
|
||||
read_entry_strings(fd, subentry);
|
||||
|
||||
/*
|
||||
* Now scan the symbol table and decide whether to
|
||||
* load.
|
||||
*/
|
||||
|
||||
if (!(link_mode & FORCEARCHIVE) &&
|
||||
!subfile_wanted_p(subentry)) {
|
||||
if (subentry->symbols)
|
||||
free(subentry->symbols);
|
||||
free(subentry);
|
||||
} else {
|
||||
/*
|
||||
* This member is needed; load it. Since we
|
||||
* are loading something on this pass, we
|
||||
* must make another pass through the symdef
|
||||
* data.
|
||||
*/
|
||||
|
||||
not_finished = 1;
|
||||
|
||||
read_entry_relocation(fd, subentry);
|
||||
enter_file_symbols(subentry);
|
||||
|
||||
if (prev)
|
||||
prev->chain = subentry;
|
||||
else
|
||||
entry->subfiles = subentry;
|
||||
prev = subentry;
|
||||
|
||||
/*
|
||||
* Clear out this member's symbols from the
|
||||
* symdef data so that following passes won't
|
||||
* waste time on them.
|
||||
*/
|
||||
|
||||
for (j = 0; j < nsymdefs; j++) {
|
||||
if (symdef_base[j].ran_off == offset)
|
||||
symdef_base[j].ran_un.ran_strx = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We'll read the strings again
|
||||
* if we need them.
|
||||
*/
|
||||
subentry->strings = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(symdef_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search a library that has no __.SYMDEF. ENTRY is the library's file_entry.
|
||||
* FD is the descriptor it is open on.
|
||||
*/
|
||||
|
||||
static void
|
||||
linear_library(fd, entry)
|
||||
int fd;
|
||||
struct file_entry *entry;
|
||||
{
|
||||
register struct file_entry *prev = 0;
|
||||
register int this_subfile_offset = SARMAG;
|
||||
|
||||
while ((link_mode & FORCEARCHIVE) ||
|
||||
undefined_global_sym_count || common_defined_global_count) {
|
||||
|
||||
int member_length;
|
||||
register struct file_entry *subentry;
|
||||
|
||||
subentry = decode_library_subfile(fd, entry,
|
||||
this_subfile_offset, &member_length);
|
||||
|
||||
if (!subentry)
|
||||
return;
|
||||
|
||||
read_entry_symbols(fd, subentry);
|
||||
subentry->strings = (char *)alloca(subentry->string_size);
|
||||
read_entry_strings(fd, subentry);
|
||||
|
||||
if (!(link_mode & FORCEARCHIVE) &&
|
||||
!subfile_wanted_p(subentry)) {
|
||||
if (subentry->symbols)
|
||||
free(subentry->symbols);
|
||||
free(subentry);
|
||||
} else {
|
||||
read_entry_relocation(fd, subentry);
|
||||
enter_file_symbols(subentry);
|
||||
|
||||
if (prev)
|
||||
prev->chain = subentry;
|
||||
else
|
||||
entry->subfiles = subentry;
|
||||
prev = subentry;
|
||||
subentry->strings = 0; /* Since space will dissapear
|
||||
* on return */
|
||||
}
|
||||
|
||||
this_subfile_offset += member_length + sizeof(struct ar_hdr);
|
||||
if (this_subfile_offset & 1)
|
||||
this_subfile_offset++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ENTRY is an entry for a library member. Its symbols have been read into
|
||||
* core, but not entered. Return nonzero if we ought to load this member.
|
||||
*/
|
||||
|
||||
static int
|
||||
subfile_wanted_p(entry)
|
||||
struct file_entry *entry;
|
||||
{
|
||||
struct localsymbol *lsp, *lspend;
|
||||
#ifdef DOLLAR_KLUDGE
|
||||
register int dollar_cond = 0;
|
||||
#endif
|
||||
|
||||
lspend = entry->symbols + entry->nsymbols;
|
||||
|
||||
for (lsp = entry->symbols; lsp < lspend; lsp++) {
|
||||
register struct nlist *p = &lsp->nzlist.nlist;
|
||||
register int type = p->n_type;
|
||||
register char *name = p->n_un.n_strx + entry->strings;
|
||||
register symbol *sp = getsym_soft(name);
|
||||
|
||||
/*
|
||||
* If the symbol has an interesting definition, we could
|
||||
* potentially want it.
|
||||
*/
|
||||
if (! (type & N_EXT)
|
||||
|| (type == (N_UNDF | N_EXT) && p->n_value == 0
|
||||
|
||||
#ifdef DOLLAR_KLUDGE
|
||||
&& name[1] != '$'
|
||||
#endif
|
||||
)
|
||||
#ifdef SET_ELEMENT_P
|
||||
|| SET_ELEMENT_P(type)
|
||||
|| set_element_prefixed_p(name)
|
||||
#endif
|
||||
)
|
||||
continue;
|
||||
|
||||
|
||||
#ifdef DOLLAR_KLUDGE
|
||||
if (name[1] == '$') {
|
||||
sp = getsym_soft(&name[2]);
|
||||
dollar_cond = 1;
|
||||
if (!sp)
|
||||
continue;
|
||||
if (sp->flags & SP_REFERENCED) {
|
||||
if (write_map) {
|
||||
print_file_name(entry, stdout);
|
||||
fprintf(stdout, " needed due to $-conditional %s\n", name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If this symbol has not been hashed, we can't be
|
||||
* looking for it.
|
||||
*/
|
||||
|
||||
if (!sp)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We don't load a file if it merely satisfies a
|
||||
* common reference (see explanation above in
|
||||
* symdef_library()).
|
||||
*/
|
||||
if ((sp->flags & GS_REFERENCED) && !sp->defined) {
|
||||
/*
|
||||
* This is a symbol we are looking for. It
|
||||
* is either not yet defined or defined as a
|
||||
* common.
|
||||
*/
|
||||
#ifdef DOLLAR_KLUDGE
|
||||
if (dollar_cond)
|
||||
continue;
|
||||
#endif
|
||||
if (type == (N_UNDF | N_EXT)) {
|
||||
/*
|
||||
* Symbol being defined as common.
|
||||
* Remember this, but don't load
|
||||
* subfile just for this.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If it didn't used to be common, up
|
||||
* the count of common symbols.
|
||||
*/
|
||||
if (!sp->common_size)
|
||||
common_defined_global_count++;
|
||||
|
||||
if (sp->common_size < p->n_value)
|
||||
sp->common_size = p->n_value;
|
||||
if (!sp->defined)
|
||||
undefined_global_sym_count--;
|
||||
sp->defined = type;
|
||||
continue;
|
||||
}
|
||||
if (sp->flags & GS_WEAK)
|
||||
/* Weak symbols don't pull archive members */
|
||||
continue;
|
||||
if (write_map) {
|
||||
print_file_name(entry, stdout);
|
||||
fprintf(stdout, " needed due to %s\n", sp->name);
|
||||
}
|
||||
return 1;
|
||||
|
||||
} else if (!sp->defined && sp->sorefs) {
|
||||
/*
|
||||
* Check for undefined symbols or commons
|
||||
* in shared objects.
|
||||
*/
|
||||
struct localsymbol *lsp;
|
||||
|
||||
for (lsp = sp->sorefs; lsp; lsp = lsp->next) {
|
||||
int type = lsp->nzlist.nlist.n_type;
|
||||
if ( (type & N_EXT) &&
|
||||
(type & N_STAB) == 0 &&
|
||||
type != (N_UNDF | N_EXT))
|
||||
break; /* We don't need it */
|
||||
}
|
||||
if (lsp != NULL)
|
||||
/*
|
||||
* We have a worthy definition in a shared
|
||||
* object that was specified ahead of the
|
||||
* archive we're examining now. So, punt.
|
||||
*/
|
||||
continue;
|
||||
|
||||
/*
|
||||
* At this point, we have an undefined shared
|
||||
* object reference. Again, if the archive member
|
||||
* defines a common we just note the its size.
|
||||
* Otherwise, the member gets included.
|
||||
*/
|
||||
|
||||
if (type == (N_UNDF|N_EXT) && p->n_value) {
|
||||
/*
|
||||
* New symbol is common, just takes its
|
||||
* size, but don't load.
|
||||
*/
|
||||
sp->common_size = p->n_value;
|
||||
sp->defined = type;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* THIS STILL MISSES the case where one shared
|
||||
* object defines a common and the next defines
|
||||
* more strongly; fix this someday by making
|
||||
* `struct glosym' and enter_global_ref() more
|
||||
* symmetric.
|
||||
*/
|
||||
|
||||
if (write_map) {
|
||||
print_file_name(entry, stdout);
|
||||
fprintf(stdout,
|
||||
" needed due to shared lib ref %s (%d)\n",
|
||||
sp->name,
|
||||
lsp ? lsp->nzlist.nlist.n_type : -1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the symbols of dynamic entity ENTRY into core. Assume it is already
|
||||
* open, on descriptor FD.
|
||||
*/
|
||||
void
|
||||
read_shared_object(fd, entry)
|
||||
struct file_entry *entry;
|
||||
int fd;
|
||||
{
|
||||
struct _dynamic dyn;
|
||||
struct section_dispatch_table sdt;
|
||||
struct nlist *np;
|
||||
struct nzlist *nzp;
|
||||
int n, i, has_nz = 0;
|
||||
|
||||
if (!(entry->flags & E_HEADER_VALID))
|
||||
read_header(fd, entry);
|
||||
|
||||
/* Read DYNAMIC structure (first in data segment) */
|
||||
if (lseek(fd, text_offset(entry) + entry->header.a_text, L_SET) ==
|
||||
(off_t)-1)
|
||||
err(1, "%s: lseek", get_file_name(entry));
|
||||
if (read(fd, &dyn, sizeof dyn) != sizeof dyn) {
|
||||
errx(1, "%s: premature EOF reading _dynamic",
|
||||
get_file_name(entry));
|
||||
}
|
||||
md_swapin__dynamic(&dyn);
|
||||
|
||||
/* Check version */
|
||||
switch (dyn.d_version) {
|
||||
default:
|
||||
errx(1, "%s: unsupported _DYNAMIC version: %d",
|
||||
get_file_name(entry), dyn.d_version);
|
||||
break;
|
||||
case LD_VERSION_SUN:
|
||||
break;
|
||||
case LD_VERSION_BSD:
|
||||
has_nz = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read Section Dispatch Table (from data segment) */
|
||||
if (lseek(fd,
|
||||
text_offset(entry) + (long)dyn.d_un.d_sdt -
|
||||
(DATA_START(entry->header) - N_DATOFF(entry->header)),
|
||||
L_SET) == (off_t)-1)
|
||||
err(1, "%s: lseek", get_file_name(entry));
|
||||
if (read(fd, &sdt, sizeof sdt) != sizeof sdt)
|
||||
errx(1, "%s: premature EOF reading sdt",
|
||||
get_file_name(entry));
|
||||
md_swapin_section_dispatch_table(&sdt);
|
||||
|
||||
/* Read symbols (text segment) */
|
||||
n = sdt.sdt_strings - sdt.sdt_nzlist;
|
||||
entry->nsymbols = n /
|
||||
(has_nz ? sizeof(struct nzlist) : sizeof(struct nlist));
|
||||
nzp = (struct nzlist *)(np = (struct nlist *)alloca (n));
|
||||
entry->symbols = (struct localsymbol *)
|
||||
xmalloc(entry->nsymbols * sizeof(struct localsymbol));
|
||||
|
||||
if (lseek(fd,
|
||||
text_offset(entry) + (long)sdt.sdt_nzlist -
|
||||
(TEXT_START(entry->header) - N_TXTOFF(entry->header)),
|
||||
L_SET) == (off_t)-1)
|
||||
err(1, "%s: lseek", get_file_name(entry));
|
||||
if (read(fd, (char *)nzp, n) != n)
|
||||
errx(1, "%s: premature EOF reading symbols ",
|
||||
get_file_name(entry));
|
||||
|
||||
if (has_nz)
|
||||
md_swapin_zsymbols(nzp, entry->nsymbols);
|
||||
else
|
||||
md_swapin_symbols(np, entry->nsymbols);
|
||||
|
||||
/* Convert to structs localsymbol */
|
||||
for (i = 0; i < entry->nsymbols; i++) {
|
||||
if (has_nz) {
|
||||
entry->symbols[i].nzlist = *nzp++;
|
||||
} else {
|
||||
entry->symbols[i].nzlist.nlist = *np++;
|
||||
entry->symbols[i].nzlist.nz_size = 0;
|
||||
}
|
||||
entry->symbols[i].symbol = NULL;
|
||||
entry->symbols[i].next = NULL;
|
||||
entry->symbols[i].entry = entry;
|
||||
entry->symbols[i].gotslot_offset = -1;
|
||||
entry->symbols[i].flags = 0;
|
||||
}
|
||||
|
||||
/* Read strings (text segment) */
|
||||
n = entry->string_size = sdt.sdt_str_sz;
|
||||
entry->strings = (char *)alloca(n);
|
||||
entry->strings_offset = text_offset(entry) + sdt.sdt_strings;
|
||||
if (lseek(fd,
|
||||
entry->strings_offset -
|
||||
(TEXT_START(entry->header) - N_TXTOFF(entry->header)),
|
||||
L_SET) == (off_t)-1)
|
||||
err(1, "%s: lseek", get_file_name(entry));
|
||||
if (read(fd, entry->strings, n) != n)
|
||||
errx(1, "%s: premature EOF reading strings",
|
||||
get_file_name(entry));
|
||||
enter_file_symbols (entry);
|
||||
entry->strings = 0;
|
||||
|
||||
/*
|
||||
* Load any subsidiary shared objects.
|
||||
*/
|
||||
if (sdt.sdt_sods) {
|
||||
struct sod sod;
|
||||
off_t offset;
|
||||
struct file_entry *prev = NULL;
|
||||
|
||||
offset = (off_t)sdt.sdt_sods;
|
||||
while (1) {
|
||||
struct file_entry *subentry;
|
||||
char *libname, name[MAXPATHLEN]; /*XXX*/
|
||||
|
||||
subentry = (struct file_entry *)
|
||||
xmalloc(sizeof(struct file_entry));
|
||||
bzero(subentry, sizeof(struct file_entry));
|
||||
subentry->superfile = entry;
|
||||
subentry->flags = E_SECONDCLASS;
|
||||
|
||||
if (lseek(fd,
|
||||
offset - (TEXT_START(entry->header) -
|
||||
N_TXTOFF(entry->header)),
|
||||
L_SET) == (off_t)-1)
|
||||
err(1, "%s: lseek", get_file_name(entry));
|
||||
if (read(fd, &sod, sizeof(sod)) != sizeof(sod))
|
||||
errx(1, "%s: premature EOF reding sod",
|
||||
get_file_name(entry));
|
||||
md_swapin_sod(&sod, 1);
|
||||
if (lseek(fd,
|
||||
(off_t)sod.sod_name - (TEXT_START(entry->header) -
|
||||
N_TXTOFF(entry->header)),
|
||||
L_SET) == (off_t)-1)
|
||||
err(1, "%s: lseek", get_file_name(entry));
|
||||
(void)read(fd, name, sizeof(name)); /*XXX*/
|
||||
if (sod.sod_library) {
|
||||
int sod_major = sod.sod_major;
|
||||
int sod_minor = sod.sod_minor;
|
||||
|
||||
libname = findshlib(name,
|
||||
&sod_major, &sod_minor, 0);
|
||||
if (libname == NULL)
|
||||
errx(1,"no shared -l%s.%d.%d available",
|
||||
name, sod.sod_major, sod.sod_minor);
|
||||
subentry->filename = libname;
|
||||
subentry->local_sym_name = concat("-l", name, "");
|
||||
} else {
|
||||
subentry->filename = strdup(name);
|
||||
subentry->local_sym_name = strdup(name);
|
||||
}
|
||||
read_file_symbols(subentry);
|
||||
|
||||
if (prev)
|
||||
prev->chain = subentry;
|
||||
else
|
||||
entry->subfiles = subentry;
|
||||
prev = subentry;
|
||||
fd = file_open(entry);
|
||||
if ((offset = (off_t)sod.sod_next) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef SUN_COMPAT
|
||||
if (link_mode & SILLYARCHIVE) {
|
||||
char *cp, *sa_name;
|
||||
char armag[SARMAG];
|
||||
int fd;
|
||||
struct file_entry *subentry;
|
||||
|
||||
sa_name = strdup(entry->filename);
|
||||
if (sa_name == NULL)
|
||||
goto out;
|
||||
cp = sa_name + strlen(sa_name) - 1;
|
||||
while (cp > sa_name) {
|
||||
if (!isdigit(*cp) && *cp != '.')
|
||||
break;
|
||||
--cp;
|
||||
}
|
||||
if (cp <= sa_name || *cp != 'o') {
|
||||
/* Not in `libxxx.so.n.m' form */
|
||||
free(sa_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*cp = 'a';
|
||||
if ((fd = open(sa_name, O_RDONLY, 0)) < 0)
|
||||
goto out;
|
||||
|
||||
/* Read archive magic */
|
||||
bzero(armag, SARMAG);
|
||||
(void)read(fd, armag, SARMAG);
|
||||
(void)close(fd);
|
||||
if (strncmp(armag, ARMAG, SARMAG) != 0) {
|
||||
warnx("%s: malformed silly archive",
|
||||
get_file_name(entry));
|
||||
goto out;
|
||||
}
|
||||
|
||||
subentry = (struct file_entry *)
|
||||
xmalloc(sizeof(struct file_entry));
|
||||
bzero(subentry, sizeof(struct file_entry));
|
||||
|
||||
entry->silly_archive = subentry;
|
||||
subentry->superfile = entry;
|
||||
subentry->filename = sa_name;
|
||||
subentry->local_sym_name = sa_name;
|
||||
subentry->flags |= E_IS_LIBRARY;
|
||||
search_library(file_open(subentry), subentry);
|
||||
out:
|
||||
;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef major
|
||||
#undef minor
|
||||
|
||||
int
|
||||
findlib(p)
|
||||
struct file_entry *p;
|
||||
{
|
||||
int i;
|
||||
int fd = -1;
|
||||
int major = -1, minor = -1;
|
||||
char *cp, *fname = NULL;
|
||||
|
||||
if (!(p->flags & E_SEARCH_DYNAMIC))
|
||||
goto dot_a;
|
||||
|
||||
fname = findshlib(p->filename, &major, &minor, 1);
|
||||
|
||||
if (fname && (fd = open(fname, O_RDONLY, 0)) > 0) {
|
||||
p->filename = fname;
|
||||
p->lib_major = major;
|
||||
p->lib_minor = minor;
|
||||
p->flags &= ~E_SEARCH_DIRS;
|
||||
return fd;
|
||||
}
|
||||
(void)free(fname);
|
||||
|
||||
dot_a:
|
||||
p->flags &= ~E_SEARCH_DYNAMIC;
|
||||
if (cp = strrchr(p->filename, '/')) {
|
||||
*cp++ = '\0';
|
||||
fname = concat(concat(p->filename, "/lib", cp), ".a", "");
|
||||
*(--cp) = '/';
|
||||
} else
|
||||
fname = concat("lib", p->filename, ".a");
|
||||
|
||||
for (i = 0; i < n_search_dirs; i++) {
|
||||
register char *path
|
||||
= concat(search_dirs[i], "/", fname);
|
||||
fd = open(path, O_RDONLY, 0);
|
||||
if (fd > 0) {
|
||||
p->filename = path;
|
||||
p->flags &= ~E_SEARCH_DIRS;
|
||||
break;
|
||||
}
|
||||
(void)free(path);
|
||||
}
|
||||
(void)free(fname);
|
||||
return fd;
|
||||
}
|
||||
|
1262
gnu/usr.bin/ld/rrs.c
1262
gnu/usr.bin/ld/rrs.c
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,10 @@
|
||||
# $NetBSD: Makefile,v 1.15 1997/03/24 22:06:36 christos Exp $
|
||||
# $NetBSD: Makefile,v 1.16 1997/04/16 16:49:43 christos Exp $
|
||||
|
||||
PROG= ld.so
|
||||
SRCS= mdprologue.S rtld.c malloc.c shlib.c etc.c md.c vfprintf.c
|
||||
MAN= rtld.1
|
||||
LDDIR?= $(.CURDIR)/..
|
||||
PICFLAG=-fpic -fno-function-cse
|
||||
CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE_ARCH) $(PICFLAG) -DRTLD -DLIBC_SCCS
|
||||
CFLAGS+=$(PICFLAG) -DRTLD -DLIBC_SCCS
|
||||
ASFLAGS+=-k
|
||||
LDFLAGS+=-Bshareable -Bsymbolic -assert nosymbolic
|
||||
.if defined(DESTDIR)
|
||||
@ -19,7 +18,7 @@ MLINKS= rtld.1 ld.so.1
|
||||
INCS=${HDRS}
|
||||
INCSDIR=/usr/include
|
||||
|
||||
.PATH: $(LDDIR) $(LDDIR)/$(MACHINE_ARCH) ${.CURDIR}/../../../../lib/libc/stdio
|
||||
.PATH: ${.CURDIR}/../../../../lib/libc/stdio
|
||||
|
||||
$(PROG):
|
||||
$(LD) -o $(PROG) $(LDFLAGS) $(OBJS) $(LDADD)
|
||||
|
@ -1,316 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Paul Kranenburg
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Paul Kranenburg.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (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: shlib.c,v 1.11 1995/06/04 21:56:30 pk Exp $
|
||||
*/
|
||||
|
||||
#ifdef sun
|
||||
char *strsep();
|
||||
int isdigit();
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <a.out.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
/*
|
||||
* Standard directories to search for files specified by -l.
|
||||
*/
|
||||
#ifndef STANDARD_SEARCH_DIRS
|
||||
#define STANDARD_SEARCH_DIRS "/usr/lib"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Actual vector of library search directories,
|
||||
* including `-L'ed and LD_LIBRARY_PATH spec'd ones.
|
||||
*/
|
||||
char **search_dirs;
|
||||
int n_search_dirs;
|
||||
|
||||
char *standard_search_dirs[] = {
|
||||
STANDARD_SEARCH_DIRS
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
add_search_dir(name)
|
||||
char *name;
|
||||
{
|
||||
n_search_dirs++;
|
||||
search_dirs = (char **)
|
||||
xrealloc(search_dirs, n_search_dirs * sizeof search_dirs[0]);
|
||||
search_dirs[n_search_dirs - 1] = strdup(name);
|
||||
}
|
||||
|
||||
void
|
||||
remove_search_dir(name)
|
||||
char *name;
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < n_search_dirs; n++) {
|
||||
if (strcmp(search_dirs[n], name))
|
||||
continue;
|
||||
free(search_dirs[n]);
|
||||
if (n < (n_search_dirs - 1))
|
||||
bcopy(&search_dirs[n+1], &search_dirs[n],
|
||||
(n_search_dirs - n - 1) * sizeof search_dirs[0]);
|
||||
n_search_dirs--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
add_search_path(path)
|
||||
char *path;
|
||||
{
|
||||
register char *cp, *dup;
|
||||
|
||||
if (path == NULL)
|
||||
return;
|
||||
|
||||
/* Add search directories from `path' */
|
||||
path = dup = strdup(path);
|
||||
while ((cp = strsep(&path, ":")) != NULL)
|
||||
add_search_dir(cp);
|
||||
free(dup);
|
||||
}
|
||||
|
||||
void
|
||||
remove_search_path(path)
|
||||
char *path;
|
||||
{
|
||||
register char *cp, *dup;
|
||||
|
||||
if (path == NULL)
|
||||
return;
|
||||
|
||||
/* Remove search directories from `path' */
|
||||
path = dup = strdup(path);
|
||||
while ((cp = strsep(&path, ":")) != NULL)
|
||||
remove_search_dir(cp);
|
||||
free(dup);
|
||||
}
|
||||
|
||||
void
|
||||
std_search_path()
|
||||
{
|
||||
int i, n;
|
||||
|
||||
/* Append standard search directories */
|
||||
n = sizeof standard_search_dirs / sizeof standard_search_dirs[0];
|
||||
for (i = 0; i < n; i++)
|
||||
add_search_dir(standard_search_dirs[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if CP points to a valid dewey number.
|
||||
* Decode and leave the result in the array DEWEY.
|
||||
* Return the number of decoded entries in DEWEY.
|
||||
*/
|
||||
|
||||
int
|
||||
getdewey(dewey, cp)
|
||||
int dewey[];
|
||||
char *cp;
|
||||
{
|
||||
int i, n;
|
||||
|
||||
for (n = 0, i = 0; i < MAXDEWEY; i++) {
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
|
||||
if (*cp == '.') cp++;
|
||||
#ifdef SUNOS_LIB_COMPAT
|
||||
if (!(isdigit)(*cp))
|
||||
#else
|
||||
if (!isdigit(*cp))
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
dewey[n++] = strtol(cp, &cp, 10);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two dewey arrays.
|
||||
* Return -1 if `d1' represents a smaller value than `d2'.
|
||||
* Return 1 if `d1' represents a greater value than `d2'.
|
||||
* Return 0 if equal.
|
||||
*/
|
||||
int
|
||||
cmpndewey(d1, n1, d2, n2)
|
||||
int d1[], d2[];
|
||||
int n1, n2;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < n1 && i < n2; i++) {
|
||||
if (d1[i] < d2[i])
|
||||
return -1;
|
||||
if (d1[i] > d2[i])
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (n1 == n2)
|
||||
return 0;
|
||||
|
||||
if (i == n1)
|
||||
return -1;
|
||||
|
||||
if (i == n2)
|
||||
return 1;
|
||||
|
||||
errx(1, "cmpndewey: cant happen");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search directories for a shared library matching the given
|
||||
* major and minor version numbers.
|
||||
*
|
||||
* MAJOR == -1 && MINOR == -1 --> find highest version
|
||||
* MAJOR != -1 && MINOR == -1 --> find highest minor version
|
||||
* MAJOR == -1 && MINOR != -1 --> invalid
|
||||
* MAJOR != -1 && MINOR != -1 --> find highest micro version
|
||||
*/
|
||||
|
||||
/* Not interested in devices right now... */
|
||||
#undef major
|
||||
#undef minor
|
||||
|
||||
char *
|
||||
findshlib(name, majorp, minorp, do_dot_a)
|
||||
char *name;
|
||||
int *majorp, *minorp;
|
||||
int do_dot_a;
|
||||
{
|
||||
int dewey[MAXDEWEY];
|
||||
int ndewey;
|
||||
int tmp[MAXDEWEY];
|
||||
int i;
|
||||
int len;
|
||||
char *lname, *path = NULL;
|
||||
int major = *majorp, minor = *minorp;
|
||||
|
||||
len = strlen(name);
|
||||
lname = (char *)alloca(len + sizeof("lib"));
|
||||
sprintf(lname, "lib%s", name);
|
||||
len += 3;
|
||||
|
||||
ndewey = 0;
|
||||
|
||||
for (i = 0; i < n_search_dirs; i++) {
|
||||
DIR *dd = opendir(search_dirs[i]);
|
||||
struct dirent *dp;
|
||||
int found_dot_a = 0;
|
||||
|
||||
if (dd == NULL)
|
||||
continue;
|
||||
|
||||
while ((dp = readdir(dd)) != NULL) {
|
||||
int n, might_take_it = 0;
|
||||
|
||||
if (do_dot_a && path == NULL &&
|
||||
dp->d_namlen == len + 2 &&
|
||||
strncmp(dp->d_name, lname, len) == 0 &&
|
||||
(dp->d_name+len)[0] == '.' &&
|
||||
(dp->d_name+len)[1] == 'a') {
|
||||
|
||||
path = concat(search_dirs[i], "/", dp->d_name);
|
||||
found_dot_a = 1;
|
||||
}
|
||||
|
||||
if (dp->d_namlen < len + 4)
|
||||
continue;
|
||||
if (strncmp(dp->d_name, lname, len) != 0)
|
||||
continue;
|
||||
if (strncmp(dp->d_name+len, ".so.", 4) != 0)
|
||||
continue;
|
||||
|
||||
if ((n = getdewey(tmp, dp->d_name+len+4)) == 0)
|
||||
continue;
|
||||
|
||||
if (major != -1 && found_dot_a) { /* XXX */
|
||||
free(path);
|
||||
path = NULL;
|
||||
found_dot_a = 0;
|
||||
}
|
||||
|
||||
if (major == -1 && minor == -1) {
|
||||
might_take_it = 1;
|
||||
} else if (major != -1 && minor == -1) {
|
||||
if (tmp[0] == major)
|
||||
might_take_it = 1;
|
||||
} else if (major != -1 && minor != -1) {
|
||||
if (tmp[0] == major)
|
||||
if (n == 1 || tmp[1] >= minor)
|
||||
might_take_it = 1;
|
||||
}
|
||||
|
||||
if (!might_take_it)
|
||||
continue;
|
||||
|
||||
if (cmpndewey(tmp, n, dewey, ndewey) <= 0)
|
||||
continue;
|
||||
|
||||
/* We have a better version */
|
||||
if (path)
|
||||
free(path);
|
||||
path = concat(search_dirs[i], "/", dp->d_name);
|
||||
found_dot_a = 0;
|
||||
bcopy(tmp, dewey, sizeof(dewey));
|
||||
ndewey = n;
|
||||
*majorp = dewey[0];
|
||||
*minorp = dewey[1];
|
||||
}
|
||||
closedir(dd);
|
||||
|
||||
if (found_dot_a)
|
||||
/*
|
||||
* There's a .a archive here.
|
||||
*/
|
||||
return path;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
@ -1,161 +0,0 @@
|
||||
/*
|
||||
* $Id: symbol.c,v 1.8 1994/06/29 11:18:55 pk Exp $ - symbol table routines
|
||||
*/
|
||||
|
||||
/* Create the symbol table entries for `etext', `edata' and `end'. */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
symbol *symtab[SYMTABSIZE]; /* The symbol table. */
|
||||
int num_hash_tab_syms; /* Number of symbols in symbol hash table. */
|
||||
|
||||
symbol *edata_symbol; /* the symbol _edata */
|
||||
symbol *etext_symbol; /* the symbol _etext */
|
||||
symbol *end_symbol; /* the symbol _end */
|
||||
symbol *got_symbol; /* the symbol __GLOBAL_OFFSET_TABLE_ */
|
||||
symbol *dynamic_symbol; /* the symbol __DYNAMIC */
|
||||
|
||||
void
|
||||
symtab_init(relocatable_output)
|
||||
int relocatable_output;
|
||||
{
|
||||
/*
|
||||
* Put linker reserved symbols into symbol table.
|
||||
*/
|
||||
#ifndef nounderscore
|
||||
#define ETEXT_SYM "_etext"
|
||||
#define EDATA_SYM "_edata"
|
||||
#define END_SYM "_end"
|
||||
#define DYN_SYM "__DYNAMIC"
|
||||
#define GOT_SYM "__GLOBAL_OFFSET_TABLE_"
|
||||
#else
|
||||
#define ETEXT_SYM "etext"
|
||||
#define EDATA_SYM "edata"
|
||||
#define END_SYM "end"
|
||||
#define DYN_SYM "_DYNAMIC"
|
||||
#define GOT_SYM "_GLOBAL_OFFSET_TABLE_"
|
||||
#endif
|
||||
|
||||
dynamic_symbol = getsym(DYN_SYM);
|
||||
dynamic_symbol->defined = relocatable_output?N_UNDF:(N_DATA | N_EXT);
|
||||
|
||||
got_symbol = getsym(GOT_SYM);
|
||||
got_symbol->defined = N_DATA | N_EXT;
|
||||
|
||||
if (relocatable_output)
|
||||
return;
|
||||
|
||||
etext_symbol = getsym(ETEXT_SYM);
|
||||
edata_symbol = getsym(EDATA_SYM);
|
||||
end_symbol = getsym(END_SYM);
|
||||
|
||||
etext_symbol->defined = N_TEXT | N_EXT;
|
||||
edata_symbol->defined = N_DATA | N_EXT;
|
||||
end_symbol->defined = N_BSS | N_EXT;
|
||||
|
||||
etext_symbol->flags |= GS_REFERENCED;
|
||||
edata_symbol->flags |= GS_REFERENCED;
|
||||
end_symbol->flags |= GS_REFERENCED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the hash code for symbol name KEY.
|
||||
*/
|
||||
|
||||
int
|
||||
hash_string (key)
|
||||
char *key;
|
||||
{
|
||||
register char *cp;
|
||||
register int k;
|
||||
|
||||
cp = key;
|
||||
k = 0;
|
||||
while (*cp)
|
||||
k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the symbol table entry for the global symbol named KEY.
|
||||
* Create one if there is none.
|
||||
*/
|
||||
|
||||
symbol *
|
||||
getsym(key)
|
||||
char *key;
|
||||
{
|
||||
register int hashval;
|
||||
register symbol *bp;
|
||||
|
||||
/* Determine the proper bucket. */
|
||||
hashval = hash_string(key) % SYMTABSIZE;
|
||||
|
||||
/* Search the bucket. */
|
||||
for (bp = symtab[hashval]; bp; bp = bp->link)
|
||||
if (strcmp(key, bp->name) == 0)
|
||||
return bp;
|
||||
|
||||
/* Nothing was found; create a new symbol table entry. */
|
||||
bp = (symbol *)xmalloc(sizeof(symbol));
|
||||
bp->name = (char *)xmalloc(strlen(key) + 1);
|
||||
strcpy (bp->name, key);
|
||||
bp->refs = 0;
|
||||
bp->defined = 0;
|
||||
bp->value = 0;
|
||||
bp->common_size = 0;
|
||||
bp->warning = 0;
|
||||
bp->undef_refs = 0;
|
||||
bp->mult_defs = 0;
|
||||
bp->alias = 0;
|
||||
bp->setv_count = 0;
|
||||
bp->symbolnum = 0;
|
||||
bp->rrs_symbolnum = 0;
|
||||
|
||||
bp->size = 0;
|
||||
bp->aux = 0;
|
||||
bp->sorefs = 0;
|
||||
bp->so_defined = 0;
|
||||
bp->def_lsp = 0;
|
||||
bp->jmpslot_offset = -1;
|
||||
bp->gotslot_offset = -1;
|
||||
bp->flags = 0;
|
||||
|
||||
/* Add the entry to the bucket. */
|
||||
bp->link = symtab[hashval];
|
||||
symtab[hashval] = bp;
|
||||
|
||||
++num_hash_tab_syms;
|
||||
|
||||
return bp;
|
||||
}
|
||||
|
||||
/* Like `getsym' but return 0 if the symbol is not already known. */
|
||||
|
||||
symbol *
|
||||
getsym_soft (key)
|
||||
char *key;
|
||||
{
|
||||
register int hashval;
|
||||
register symbol *bp;
|
||||
|
||||
/* Determine which bucket. */
|
||||
hashval = hash_string(key) % SYMTABSIZE;
|
||||
|
||||
/* Search the bucket. */
|
||||
for (bp = symtab[hashval]; bp; bp = bp->link)
|
||||
if (strcmp(key, bp->name) == 0)
|
||||
return bp;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,359 +0,0 @@
|
||||
/*-
|
||||
*
|
||||
* This code is derived from software copyrighted by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* from: @(#)symseg.h 5.4 (Berkeley) 4/30/91
|
||||
* $Id: symseg.h,v 1.3 1993/12/08 10:14:07 pk Exp $
|
||||
*/
|
||||
|
||||
/* GDB symbol table format definitions.
|
||||
Copyright (C) 1987, 1988 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
||||
GNU CC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU CC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU CC; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Format of GDB symbol table data.
|
||||
There is one symbol segment for each source file or
|
||||
independant compilation. These segments are simply concatenated
|
||||
to form the GDB symbol table. A zero word where the beginning
|
||||
of a segment is expected indicates there are no more segments.
|
||||
|
||||
Format of a symbol segment:
|
||||
|
||||
The symbol segment begins with a word containing 1
|
||||
if it is in the format described here. Other formats may
|
||||
be designed, with other code numbers.
|
||||
|
||||
The segment contains many objects which point at each other.
|
||||
The pointers are offsets in bytes from the beginning of the segment.
|
||||
Thus, each segment can be loaded into core and its pointers relocated
|
||||
to make valid in-core pointers.
|
||||
|
||||
All the data objects in the segment can be found indirectly from
|
||||
one of them, the root object, of type `struct symbol_root'.
|
||||
It appears at the beginning of the segment.
|
||||
|
||||
The total size of the segment, in bytes, appears as the `length'
|
||||
field of this object. This size includes the size of the
|
||||
root object.
|
||||
|
||||
All the object data types are defined here to contain pointer types
|
||||
appropriate for in-core use on a relocated symbol segment.
|
||||
Casts to and from type int are required for working with
|
||||
unrelocated symbol segments such as are found in the file.
|
||||
|
||||
The ldsymaddr word is filled in by the loader to contain
|
||||
the offset (in bytes) within the ld symbol table
|
||||
of the first nonglobal symbol from this compilation.
|
||||
This makes it possible to match those symbols
|
||||
(which contain line number information) reliably with
|
||||
the segment they go with.
|
||||
|
||||
Core addresses within the program that appear in the symbol segment
|
||||
are not relocated by the loader. They are inserted by the assembler
|
||||
and apply to addresses as output by the assembler, so GDB must
|
||||
relocate them when it loads the symbol segment. It gets the information
|
||||
on how to relocate from the textrel, datarel, bssrel, databeg and bssbeg
|
||||
words of the root object.
|
||||
|
||||
The words textrel, datarel and bssrel
|
||||
are filled in by ld with the amounts to relocate within-the-file
|
||||
text, data and bss addresses by; databeg and bssbeg can be
|
||||
used to tell which kind of relocation an address needs. */
|
||||
|
||||
enum language {language_c};
|
||||
|
||||
struct symbol_root
|
||||
{
|
||||
int format; /* Data format version */
|
||||
int length; /* # bytes in this symbol segment */
|
||||
int ldsymoff; /* Offset in ld symtab of this file's syms */
|
||||
int textrel; /* Relocation for text addresses */
|
||||
int datarel; /* Relocation for data addresses */
|
||||
int bssrel; /* Relocation for bss addresses */
|
||||
char *filename; /* Name of main source file compiled */
|
||||
char *filedir; /* Name of directory it was reached from */
|
||||
struct blockvector *blockvector; /* Vector of all symbol-naming blocks */
|
||||
struct typevector *typevector; /* Vector of all data types */
|
||||
enum language language; /* Code identifying the language used */
|
||||
char *version; /* Version info. Not fully specified */
|
||||
char *compilation; /* Compilation info. Not fully specified */
|
||||
int databeg; /* Address within the file of data start */
|
||||
int bssbeg; /* Address within the file of bss start */
|
||||
struct sourcevector *sourcevector; /* Vector of line-number info */
|
||||
};
|
||||
|
||||
/* All data types of symbols in the compiled program
|
||||
are represented by `struct type' objects.
|
||||
All of these objects are pointed to by the typevector.
|
||||
The type vector may have empty slots that contain zero. */
|
||||
|
||||
struct typevector
|
||||
{
|
||||
int length; /* Number of types described */
|
||||
struct type *type[1];
|
||||
};
|
||||
|
||||
/* Different kinds of data types are distinguished by the `code' field. */
|
||||
|
||||
enum type_code
|
||||
{
|
||||
TYPE_CODE_UNDEF, /* Not used; catches errors */
|
||||
TYPE_CODE_PTR, /* Pointer type */
|
||||
TYPE_CODE_ARRAY, /* Array type, lower bound zero */
|
||||
TYPE_CODE_STRUCT, /* C struct or Pascal record */
|
||||
TYPE_CODE_UNION, /* C union or Pascal variant part */
|
||||
TYPE_CODE_ENUM, /* Enumeration type */
|
||||
TYPE_CODE_FUNC, /* Function type */
|
||||
TYPE_CODE_INT, /* Integer type */
|
||||
TYPE_CODE_FLT, /* Floating type */
|
||||
TYPE_CODE_VOID, /* Void type (values zero length) */
|
||||
TYPE_CODE_SET, /* Pascal sets */
|
||||
TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */
|
||||
TYPE_CODE_PASCAL_ARRAY, /* Array with explicit type of index */
|
||||
};
|
||||
|
||||
/* This appears in a type's flags word for an unsigned integer type. */
|
||||
#define TYPE_FLAG_UNSIGNED 1
|
||||
|
||||
/* Other flag bits are used with GDB. */
|
||||
|
||||
struct type
|
||||
{
|
||||
/* Code for kind of type */
|
||||
enum type_code code;
|
||||
/* Name of this type, or zero if none.
|
||||
This is used for printing only.
|
||||
Type names specified as input are defined by symbols. */
|
||||
char *name;
|
||||
/* Length in bytes of storage for a value of this type */
|
||||
int length;
|
||||
/* For a pointer type, describes the type of object pointed to.
|
||||
For an array type, describes the type of the elements.
|
||||
For a function type, describes the type of the value.
|
||||
Unused otherwise. */
|
||||
struct type *target_type;
|
||||
/* Type that is a pointer to this type.
|
||||
Zero if no such pointer-to type is known yet.
|
||||
The debugger may add the address of such a type
|
||||
if it has to construct one later. */
|
||||
struct type *pointer_type;
|
||||
/* Type that is a function returning this type.
|
||||
Zero if no such function type is known here.
|
||||
The debugger may add the address of such a type
|
||||
if it has to construct one later. */
|
||||
struct type *function_type;
|
||||
/* Flags about this type. */
|
||||
short flags;
|
||||
/* Number of fields described for this type */
|
||||
short nfields;
|
||||
/* For structure and union types, a description of each field.
|
||||
For set and pascal array types, there is one "field",
|
||||
whose type is the domain type of the set or array.
|
||||
For range types, there are two "fields",
|
||||
the minimum and maximum values (both inclusive).
|
||||
For enum types, each possible value is described by one "field".
|
||||
For range types, there are two "fields", that record constant values
|
||||
(inclusive) for the minimum and maximum.
|
||||
|
||||
Using a pointer to a separate array of fields
|
||||
allows all types to have the same size, which is useful
|
||||
because we can allocate the space for a type before
|
||||
we know what to put in it. */
|
||||
struct field
|
||||
{
|
||||
/* Position of this field, counting in bits from start of
|
||||
containing structure. For a function type, this is the
|
||||
position in the argument list of this argument.
|
||||
For a range bound or enum value, this is the value itself. */
|
||||
int bitpos;
|
||||
/* Size of this field, in bits, or zero if not packed.
|
||||
For an unpacked field, the field's type's length
|
||||
says how many bytes the field occupies. */
|
||||
int bitsize;
|
||||
/* In a struct or enum type, type of this field.
|
||||
In a function type, type of this argument.
|
||||
In an array type, the domain-type of the array. */
|
||||
struct type *type;
|
||||
/* Name of field, value or argument.
|
||||
Zero for range bounds and array domains. */
|
||||
char *name;
|
||||
} *fields;
|
||||
};
|
||||
|
||||
/* All of the name-scope contours of the program
|
||||
are represented by `struct block' objects.
|
||||
All of these objects are pointed to by the blockvector.
|
||||
|
||||
Each block represents one name scope.
|
||||
Each lexical context has its own block.
|
||||
|
||||
The first two blocks in the blockvector are special.
|
||||
The first one contains all the symbols defined in this compilation
|
||||
whose scope is the entire program linked together.
|
||||
The second one contains all the symbols whose scope is the
|
||||
entire compilation excluding other separate compilations.
|
||||
In C, these correspond to global symbols and static symbols.
|
||||
|
||||
Each block records a range of core addresses for the code that
|
||||
is in the scope of the block. The first two special blocks
|
||||
give, for the range of code, the entire range of code produced
|
||||
by the compilation that the symbol segment belongs to.
|
||||
|
||||
The blocks appear in the blockvector
|
||||
in order of increasing starting-address,
|
||||
and, within that, in order of decreasing ending-address.
|
||||
|
||||
This implies that within the body of one function
|
||||
the blocks appear in the order of a depth-first tree walk. */
|
||||
|
||||
struct blockvector
|
||||
{
|
||||
/* Number of blocks in the list. */
|
||||
int nblocks;
|
||||
/* The blocks themselves. */
|
||||
struct block *block[1];
|
||||
};
|
||||
|
||||
struct block
|
||||
{
|
||||
/* Addresses in the executable code that are in this block.
|
||||
Note: in an unrelocated symbol segment in a file,
|
||||
these are always zero. They can be filled in from the
|
||||
N_LBRAC and N_RBRAC symbols in the loader symbol table. */
|
||||
int startaddr, endaddr;
|
||||
/* The symbol that names this block,
|
||||
if the block is the body of a function;
|
||||
otherwise, zero.
|
||||
Note: In an unrelocated symbol segment in an object file,
|
||||
this field may be zero even when the block has a name.
|
||||
That is because the block is output before the name
|
||||
(since the name resides in a higher block).
|
||||
Since the symbol does point to the block (as its value),
|
||||
it is possible to find the block and set its name properly. */
|
||||
struct symbol *function;
|
||||
/* The `struct block' for the containing block, or 0 if none. */
|
||||
/* Note that in an unrelocated symbol segment in an object file
|
||||
this pointer may be zero when the correct value should be
|
||||
the second special block (for symbols whose scope is one compilation).
|
||||
This is because the compiler ouptuts the special blocks at the
|
||||
very end, after the other blocks. */
|
||||
struct block *superblock;
|
||||
/* Number of local symbols. */
|
||||
int nsyms;
|
||||
/* The symbols. */
|
||||
struct symbol *sym[1];
|
||||
};
|
||||
|
||||
/* Represent one symbol name; a variable, constant, function or typedef. */
|
||||
|
||||
/* Different name spaces for symbols. Looking up a symbol specifies
|
||||
a namespace and ignores symbol definitions in other name spaces.
|
||||
|
||||
VAR_NAMESPACE is the usual namespace.
|
||||
In C, this contains variables, function names, typedef names
|
||||
and enum type values.
|
||||
|
||||
STRUCT_NAMESPACE is used in C to hold struct, union and enum type names.
|
||||
Thus, if `struct foo' is used in a C program,
|
||||
it produces a symbol named `foo' in the STRUCT_NAMESPACE.
|
||||
|
||||
LABEL_NAMESPACE may be used for names of labels (for gotos);
|
||||
currently it is not used and labels are not recorded at all. */
|
||||
|
||||
/* For a non-global symbol allocated statically,
|
||||
the correct core address cannot be determined by the compiler.
|
||||
The compiler puts an index number into the symbol's value field.
|
||||
This index number can be matched with the "desc" field of
|
||||
an entry in the loader symbol table. */
|
||||
|
||||
enum namespace
|
||||
{
|
||||
UNDEF_NAMESPACE, VAR_NAMESPACE, STRUCT_NAMESPACE, LABEL_NAMESPACE,
|
||||
};
|
||||
|
||||
/* An address-class says where to find the value of the symbol in core. */
|
||||
|
||||
enum address_class
|
||||
{
|
||||
LOC_UNDEF, /* Not used; catches errors */
|
||||
LOC_CONST, /* Value is constant int */
|
||||
LOC_STATIC, /* Value is at fixed address */
|
||||
LOC_REGISTER, /* Value is in register */
|
||||
LOC_ARG, /* Value is at spec'd position in arglist */
|
||||
LOC_LOCAL, /* Value is at spec'd pos in stack frame */
|
||||
LOC_TYPEDEF, /* Value not used; definition in SYMBOL_TYPE
|
||||
Symbols in the namespace STRUCT_NAMESPACE
|
||||
all have this class. */
|
||||
LOC_LABEL, /* Value is address in the code */
|
||||
LOC_BLOCK, /* Value is address of a `struct block'.
|
||||
Function names have this class. */
|
||||
LOC_EXTERNAL, /* Value is at address not in this compilation.
|
||||
This is used for .comm symbols
|
||||
and for extern symbols within functions.
|
||||
Inside GDB, this is changed to LOC_STATIC once the
|
||||
real address is obtained from a loader symbol. */
|
||||
LOC_CONST_BYTES /* Value is a constant byte-sequence. */
|
||||
};
|
||||
|
||||
struct symbol
|
||||
{
|
||||
/* Symbol name */
|
||||
char *name;
|
||||
/* Name space code. */
|
||||
enum namespace namespace;
|
||||
/* Address class */
|
||||
enum address_class class;
|
||||
/* Data type of value */
|
||||
struct type *type;
|
||||
/* constant value, or address if static, or register number,
|
||||
or offset in arguments, or offset in stack frame. */
|
||||
union
|
||||
{
|
||||
long value;
|
||||
struct block *block; /* for LOC_BLOCK */
|
||||
char *bytes; /* for LOC_CONST_BYTES */
|
||||
}
|
||||
value;
|
||||
};
|
||||
|
||||
/* Source-file information.
|
||||
This describes the relation between source files and line numbers
|
||||
and addresses in the program text. */
|
||||
|
||||
struct sourcevector
|
||||
{
|
||||
int length; /* Number of source files described */
|
||||
struct source *source[1]; /* Descriptions of the files */
|
||||
};
|
||||
|
||||
/* Line number and address of one line. */
|
||||
|
||||
struct line
|
||||
{
|
||||
int linenum;
|
||||
int address;
|
||||
};
|
||||
|
||||
/* All the information on one source file. */
|
||||
|
||||
struct source
|
||||
{
|
||||
char *name; /* Name of file */
|
||||
int nlines; /* Number of lines that follow */
|
||||
struct line lines[1]; /* Information on each line */
|
||||
};
|
@ -1,758 +0,0 @@
|
||||
/*
|
||||
* $Id: warnings.c,v 1.18 1994/12/28 10:37:38 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/errno.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <ar.h>
|
||||
#include <ranlib.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <string.h>
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
static int reported_undefineds;
|
||||
|
||||
/*
|
||||
* Print the filename of ENTRY on OUTFILE (a stdio stream),
|
||||
* and then a newline.
|
||||
*/
|
||||
|
||||
void
|
||||
prline_file_name (entry, outfile)
|
||||
struct file_entry *entry;
|
||||
FILE *outfile;
|
||||
{
|
||||
print_file_name (entry, outfile);
|
||||
fprintf (outfile, "\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the filename of ENTRY on OUTFILE (a stdio stream).
|
||||
*/
|
||||
|
||||
void
|
||||
print_file_name (entry, outfile)
|
||||
struct file_entry *entry;
|
||||
FILE *outfile;
|
||||
{
|
||||
if (entry == NULL) {
|
||||
fprintf (outfile, "NULL");
|
||||
}
|
||||
|
||||
if (entry->superfile) {
|
||||
print_file_name (entry->superfile, outfile);
|
||||
fprintf (outfile, "(%s)", entry->filename);
|
||||
} else
|
||||
fprintf (outfile, "%s", entry->filename);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the filename of entry as a string (malloc'd for the purpose)
|
||||
*/
|
||||
|
||||
char *
|
||||
get_file_name (entry)
|
||||
struct file_entry *entry;
|
||||
{
|
||||
char *result, *supfile;
|
||||
|
||||
if (entry == NULL) {
|
||||
return (char *)strdup("NULL");
|
||||
}
|
||||
|
||||
if (entry->superfile) {
|
||||
supfile = get_file_name(entry->superfile);
|
||||
result = (char *)
|
||||
xmalloc(strlen(supfile) + strlen(entry->filename) + 3);
|
||||
(void)sprintf(result, "%s(%s)", supfile, entry->filename);
|
||||
free(supfile);
|
||||
|
||||
} else {
|
||||
result = (char *)xmalloc(strlen(entry->filename) + 1);
|
||||
strcpy(result, entry->filename);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Print a complete or partial map of the output file. */
|
||||
|
||||
static void describe_file_sections __P((struct file_entry *, FILE *));
|
||||
static void list_file_locals __P((struct file_entry *, FILE *));
|
||||
|
||||
void
|
||||
print_symbols(outfile)
|
||||
FILE *outfile;
|
||||
{
|
||||
fprintf(outfile, "\nFiles:\n\n");
|
||||
each_file(describe_file_sections, (void *)outfile);
|
||||
|
||||
fprintf(outfile, "\nGlobal symbols:\n\n");
|
||||
FOR_EACH_SYMBOL(i, sp) {
|
||||
fprintf(outfile, " %s: ", sp->name);
|
||||
if (!(sp->flags & GS_REFERENCED))
|
||||
fprintf(outfile, "unreferenced");
|
||||
else if (sp->so_defined)
|
||||
fprintf(outfile, "sodefined");
|
||||
else if (!sp->defined)
|
||||
fprintf(outfile, "undefined");
|
||||
else if (sp->defined == (N_UNDF|N_EXT))
|
||||
fprintf(outfile, "common: size %#x", sp->common_size);
|
||||
else
|
||||
fprintf(outfile, "type %d, value %#x, size %#x",
|
||||
sp->defined, sp->value, sp->size);
|
||||
if (sp->alias)
|
||||
fprintf(outfile, ", aliased to %s", sp->alias->name);
|
||||
fprintf(outfile, "\n");
|
||||
} END_EACH_SYMBOL;
|
||||
|
||||
each_file(list_file_locals, (void *)outfile);
|
||||
}
|
||||
|
||||
static void
|
||||
describe_file_sections(entry, outfile)
|
||||
struct file_entry *entry;
|
||||
FILE *outfile;
|
||||
{
|
||||
fprintf(outfile, " ");
|
||||
print_file_name(entry, outfile);
|
||||
if (entry->flags & (E_JUST_SYMS | E_DYNAMIC))
|
||||
fprintf(outfile, " symbols only\n");
|
||||
else
|
||||
fprintf(outfile, " text %x(%x), data %x(%x), bss %x(%x) hex\n",
|
||||
entry->text_start_address, entry->header.a_text,
|
||||
entry->data_start_address, entry->header.a_data,
|
||||
entry->bss_start_address, entry->header.a_bss);
|
||||
}
|
||||
|
||||
static void
|
||||
list_file_locals (entry, outfile)
|
||||
struct file_entry *entry;
|
||||
FILE *outfile;
|
||||
{
|
||||
struct localsymbol *lsp, *lspend;
|
||||
|
||||
entry->strings = (char *)alloca(entry->string_size);
|
||||
read_entry_strings (file_open(entry), entry);
|
||||
|
||||
fprintf (outfile, "\nLocal symbols of ");
|
||||
print_file_name (entry, outfile);
|
||||
fprintf (outfile, ":\n\n");
|
||||
|
||||
lspend = entry->symbols + entry->nsymbols;
|
||||
for (lsp = entry->symbols; lsp < lspend; lsp++) {
|
||||
register struct nlist *p = &lsp->nzlist.nlist;
|
||||
/*
|
||||
* If this is a definition,
|
||||
* update it if necessary by this file's start address.
|
||||
*/
|
||||
if (!(p->n_type & (N_STAB | N_EXT)))
|
||||
fprintf(outfile, " %s: 0x%x\n",
|
||||
entry->strings + p->n_un.n_strx, p->n_value);
|
||||
}
|
||||
|
||||
entry->strings = 0; /* All done with them. */
|
||||
}
|
||||
|
||||
|
||||
/* Static vars for do_warnings and subroutines of it */
|
||||
static int list_unresolved_refs; /* List unresolved refs */
|
||||
static int list_multiple_defs; /* List multiple definitions */
|
||||
|
||||
static struct line_debug_entry *init_debug_scan __P((int, struct file_entry *));
|
||||
static int next_debug_entry __P((int, struct line_debug_entry *));
|
||||
|
||||
/*
|
||||
* Structure for communication between do_file_warnings and it's
|
||||
* helper routines. Will in practice be an array of three of these:
|
||||
* 0) Current line, 1) Next line, 2) Source file info.
|
||||
*/
|
||||
struct line_debug_entry
|
||||
{
|
||||
int line;
|
||||
char *filename;
|
||||
struct localsymbol *sym;
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper routines for do_file_warnings.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return an integer less than, equal to, or greater than 0 as per the
|
||||
* relation between the two relocation entries. Used by qsort.
|
||||
*/
|
||||
|
||||
static int
|
||||
reloc_cmp(rel1, rel2)
|
||||
struct relocation_info *rel1, *rel2;
|
||||
{
|
||||
return RELOC_ADDRESS(rel1) - RELOC_ADDRESS(rel2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Moves to the next debugging symbol in the file. USE_DATA_SYMBOLS
|
||||
* determines the type of the debugging symbol to look for (DSLINE or
|
||||
* SLINE). STATE_POINTER keeps track of the old and new locatiosn in
|
||||
* the file. It assumes that state_pointer[1] is valid; ie
|
||||
* that it.sym points into some entry in the symbol table. If
|
||||
* state_pointer[1].sym == 0, this routine should not be called.
|
||||
*/
|
||||
|
||||
static int
|
||||
next_debug_entry(use_data_symbols, state_pointer)
|
||||
register int use_data_symbols;
|
||||
/* Next must be passed by reference! */
|
||||
struct line_debug_entry state_pointer[3];
|
||||
{
|
||||
register struct line_debug_entry
|
||||
*current = state_pointer,
|
||||
*next = state_pointer + 1,
|
||||
/* Used to store source file */
|
||||
*source = state_pointer + 2;
|
||||
|
||||
struct file_entry *entry = (struct file_entry *)source->sym;
|
||||
struct localsymbol *lspend = entry->symbols + entry->nsymbols;
|
||||
|
||||
|
||||
current->sym = next->sym;
|
||||
current->line = next->line;
|
||||
current->filename = next->filename;
|
||||
|
||||
while (++(next->sym) < lspend) {
|
||||
|
||||
struct nlist *np = &next->sym->nzlist.nlist;
|
||||
|
||||
/*
|
||||
* n_type is a char, and N_SOL, N_EINCL and N_BINCL are > 0x80,
|
||||
* so may look negative...therefore, must mask to low bits
|
||||
*/
|
||||
switch (np->n_type & 0xff) {
|
||||
case N_SLINE:
|
||||
if (use_data_symbols)
|
||||
continue;
|
||||
next->line = np->n_desc;
|
||||
return 1;
|
||||
case N_DSLINE:
|
||||
if (!use_data_symbols)
|
||||
continue;
|
||||
next->line = np->n_desc;
|
||||
return 1;
|
||||
#ifdef HAVE_SUN_STABS
|
||||
case N_EINCL:
|
||||
next->filename = source->filename;
|
||||
continue;
|
||||
#endif
|
||||
case N_SO:
|
||||
source->filename = np->n_un.n_strx + entry->strings;
|
||||
source->line++;
|
||||
#ifdef HAVE_SUN_STABS
|
||||
case N_BINCL:
|
||||
#endif
|
||||
case N_SOL:
|
||||
next->filename = np->n_un.n_strx + entry->strings;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
next->sym = (struct localsymbol *)0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a structure to save the state of a scan through the debug symbols.
|
||||
* USE_DATA_SYMBOLS is set if we should be scanning for DSLINE's instead of
|
||||
* SLINE's. ENTRY is the file entry which points at the symbols to use.
|
||||
*/
|
||||
|
||||
static struct line_debug_entry *
|
||||
init_debug_scan(use_data_symbols, entry)
|
||||
int use_data_symbols;
|
||||
struct file_entry *entry;
|
||||
{
|
||||
register struct localsymbol *lsp, *lspend;
|
||||
struct line_debug_entry *state_pointer, *current, *next, *source;
|
||||
|
||||
state_pointer = (struct line_debug_entry *)
|
||||
xmalloc(3 * sizeof(*state_pointer));
|
||||
|
||||
current = state_pointer,
|
||||
next = state_pointer + 1,
|
||||
source = state_pointer + 2; /* Used to store source file */
|
||||
|
||||
lspend = entry->symbols+entry->nsymbols;
|
||||
|
||||
for (lsp = entry->symbols; lsp < lspend; lsp++)
|
||||
if (lsp->nzlist.nlist.n_type == N_SO)
|
||||
break;
|
||||
|
||||
if (lsp >= lspend) {
|
||||
/* I believe this translates to "We lose" */
|
||||
current->filename = next->filename = entry->filename;
|
||||
current->line = next->line = -1;
|
||||
current->sym = next->sym = (struct localsymbol *)0;
|
||||
return state_pointer;
|
||||
}
|
||||
next->line = source->line = 0;
|
||||
next->filename = source->filename
|
||||
= (lsp->nzlist.nlist.n_un.n_strx + entry->strings);
|
||||
source->sym = (struct localsymbol *)entry;
|
||||
next->sym = lsp;
|
||||
|
||||
/* To setup next */
|
||||
next_debug_entry(use_data_symbols, state_pointer);
|
||||
|
||||
if (!next->sym) { /* No line numbers for this section; */
|
||||
/* setup output results as appropriate */
|
||||
if (source->line) {
|
||||
current->filename = source->filename = entry->filename;
|
||||
current->line = -1; /* Don't print lineno */
|
||||
} else {
|
||||
current->filename = source->filename;
|
||||
current->line = 0;
|
||||
}
|
||||
return state_pointer;
|
||||
}
|
||||
/* To setup current */
|
||||
next_debug_entry(use_data_symbols, state_pointer);
|
||||
|
||||
return state_pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Takes an ADDRESS (in either text or data space) and a STATE_POINTER which
|
||||
* describes the current location in the implied scan through the debug
|
||||
* symbols within the file which ADDRESS is within, and returns the source
|
||||
* line number which corresponds to ADDRESS.
|
||||
*/
|
||||
|
||||
static int
|
||||
address_to_line(address, state_pointer)
|
||||
unsigned long address;
|
||||
/* Next must be passed by reference! */
|
||||
struct line_debug_entry state_pointer[3];
|
||||
{
|
||||
struct line_debug_entry *current, *next, *tmp_pointer;
|
||||
int use_data_symbols;
|
||||
|
||||
current = state_pointer;
|
||||
next = state_pointer + 1;
|
||||
|
||||
if (next->sym)
|
||||
use_data_symbols =
|
||||
(next->sym->nzlist.nlist.n_type & N_TYPE) == N_DATA;
|
||||
else
|
||||
return current->line;
|
||||
|
||||
/* Go back to the beginning if we've already passed it. */
|
||||
if (current->sym->nzlist.nlist.n_value > address) {
|
||||
tmp_pointer = init_debug_scan(use_data_symbols,
|
||||
(struct file_entry *)
|
||||
((state_pointer + 2)->sym));
|
||||
state_pointer[0] = tmp_pointer[0];
|
||||
state_pointer[1] = tmp_pointer[1];
|
||||
state_pointer[2] = tmp_pointer[2];
|
||||
free(tmp_pointer);
|
||||
}
|
||||
|
||||
/* If we're still in a bad way, return -1, meaning invalid line. */
|
||||
if (current->sym->nzlist.nlist.n_value > address)
|
||||
return -1;
|
||||
|
||||
while (next->sym
|
||||
&& next->sym->nzlist.nlist.n_value <= address
|
||||
&& next_debug_entry(use_data_symbols, state_pointer));
|
||||
|
||||
return current->line;
|
||||
}
|
||||
|
||||
|
||||
/* Macros for manipulating bitvectors. */
|
||||
#define BIT_SET_P(bv, index) ((bv)[(index) >> 3] & 1 << ((index) & 0x7))
|
||||
#define SET_BIT(bv, index) ((bv)[(index) >> 3] |= 1 << ((index) & 0x7))
|
||||
|
||||
/*
|
||||
* This routine will scan through the relocation data of file ENTRY, printing
|
||||
* out references to undefined symbols and references to symbols defined in
|
||||
* files with N_WARNING symbols. If DATA_SEGMENT is non-zero, it will scan
|
||||
* the data relocation segment (and use N_DSLINE symbols to track line
|
||||
* number); otherwise it will scan the text relocation segment. Warnings
|
||||
* will be printed on the output stream OUTFILE. Eventually, every nlist
|
||||
* symbol mapped through will be marked in the NLIST_BITVECTOR, so we don't
|
||||
* repeat ourselves when we scan the nlists themselves.
|
||||
*/
|
||||
|
||||
static void
|
||||
do_relocation_warnings(entry, data_segment, outfile, nlist_bitvector)
|
||||
struct file_entry *entry;
|
||||
int data_segment;
|
||||
FILE *outfile;
|
||||
unsigned char *nlist_bitvector;
|
||||
{
|
||||
struct relocation_info *rp, *erp;
|
||||
int start_of_segment;
|
||||
struct localsymbol *start_of_syms;
|
||||
struct line_debug_entry *state_pointer, *current;
|
||||
/* Assigned to generally static values; should not be written into. */
|
||||
char *errfmt;
|
||||
/*
|
||||
* Assigned to alloca'd values cand copied into; should be freed when
|
||||
* done.
|
||||
*/
|
||||
char *errmsg;
|
||||
int invalidate_line_number;
|
||||
|
||||
rp = data_segment ? entry->datarel : entry->textrel;
|
||||
erp = data_segment ? (rp + entry->ndatarel) : (rp + entry->ntextrel);
|
||||
start_of_syms = entry->symbols;
|
||||
start_of_segment = (data_segment ?
|
||||
entry->data_start_address :
|
||||
entry->text_start_address);
|
||||
state_pointer = init_debug_scan(data_segment != 0, entry);
|
||||
current = state_pointer;
|
||||
|
||||
/*
|
||||
* We need to sort the relocation info here. Sheesh, so much effort
|
||||
* for one lousy error optimization.
|
||||
*/
|
||||
qsort(rp, erp - rp, sizeof(rp[0]), reloc_cmp);
|
||||
|
||||
for (; rp < erp; rp++) {
|
||||
register struct localsymbol *lsp;
|
||||
register symbol *g;
|
||||
|
||||
/*
|
||||
* If the relocation isn't resolved through a symbol, continue.
|
||||
*/
|
||||
if (!RELOC_EXTERN_P(rp))
|
||||
continue;
|
||||
|
||||
lsp = &entry->symbols[RELOC_SYMBOL(rp)];
|
||||
|
||||
/*
|
||||
* Local symbols shouldn't ever be used by relocation info,
|
||||
* so the next should be safe. This is, of course, wrong.
|
||||
* References to local BSS symbols can be the targets of
|
||||
* relocation info, and they can (must) be resolved through
|
||||
* symbols. However, these must be defined properly, (the
|
||||
* assembler would have caught it otherwise), so we can
|
||||
* ignore these cases.
|
||||
*/
|
||||
|
||||
if ((g = lsp->symbol) == NULL)
|
||||
continue;
|
||||
|
||||
if (!(lsp->nzlist.nz_type & N_EXT) &&
|
||||
!SET_ELEMENT_P(lsp->nzlist.nz_type)) {
|
||||
warnx("internal error: `%s' N_EXT not set", g->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
errmsg = 0;
|
||||
|
||||
if (!g->defined && !g->so_defined && list_unresolved_refs) {
|
||||
/* Mark as being noted by relocation warning pass. */
|
||||
SET_BIT(nlist_bitvector, lsp - start_of_syms);
|
||||
|
||||
if (g->undef_refs == 0)
|
||||
reported_undefineds++;
|
||||
if (g->undef_refs >= MAX_UREFS_PRINTED)
|
||||
/* Listed too many */
|
||||
continue;
|
||||
/* Undefined symbol which we should mention */
|
||||
|
||||
if (++(g->undef_refs) == MAX_UREFS_PRINTED) {
|
||||
errfmt = "More undefined symbol %s refs follow";
|
||||
invalidate_line_number = 1;
|
||||
} else {
|
||||
errfmt =
|
||||
"Undefined symbol `%s' referenced from %s segment";
|
||||
invalidate_line_number = 0;
|
||||
}
|
||||
} else { /* Defined */
|
||||
/* Potential symbol warning here */
|
||||
if (!g->warning)
|
||||
continue;
|
||||
|
||||
if (BIT_SET_P(nlist_bitvector, lsp - start_of_syms))
|
||||
continue;
|
||||
|
||||
/* Mark as being noted by relocation warning pass. */
|
||||
SET_BIT(nlist_bitvector, lsp - start_of_syms);
|
||||
|
||||
errfmt = 0;
|
||||
errmsg = g->warning;
|
||||
invalidate_line_number = 0;
|
||||
}
|
||||
|
||||
|
||||
/* If errfmt == 0, errmsg has already been defined. */
|
||||
if (errfmt != 0) {
|
||||
char *nm;
|
||||
|
||||
nm = g->name;
|
||||
errmsg = (char *)
|
||||
xmalloc(strlen(errfmt) + strlen(nm) + 1);
|
||||
sprintf(errmsg, errfmt, nm, data_segment?"data":"text");
|
||||
if (nm != g->name)
|
||||
free(nm);
|
||||
}
|
||||
address_to_line(RELOC_ADDRESS(rp) + start_of_segment,
|
||||
state_pointer);
|
||||
|
||||
if (current->line >= 0)
|
||||
fprintf(outfile, "%s:%d: %s\n",
|
||||
current->filename,
|
||||
invalidate_line_number ? 0 : current->line,
|
||||
errmsg);
|
||||
else
|
||||
fprintf(outfile, "%s: %s\n", current->filename, errmsg);
|
||||
|
||||
if (errfmt != 0)
|
||||
free(errmsg);
|
||||
}
|
||||
|
||||
free(state_pointer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print on OUTFILE a list of all warnings generated by references and/or
|
||||
* definitions in the file ENTRY. List source file and line number if
|
||||
* possible, just the .o file if not.
|
||||
*/
|
||||
|
||||
void
|
||||
do_file_warnings (entry, outfile)
|
||||
struct file_entry *entry;
|
||||
FILE *outfile;
|
||||
{
|
||||
int nsym;
|
||||
int i;
|
||||
char *errfmt, *file_name;
|
||||
int line_number;
|
||||
int dont_allow_symbol_name;
|
||||
u_char *nlist_bitvector;
|
||||
struct line_debug_entry *text_scan, *data_scan;
|
||||
|
||||
nsym = entry->nsymbols;
|
||||
nlist_bitvector = (u_char *)alloca((nsym >> 3) + 1);
|
||||
bzero(nlist_bitvector, (nsym >> 3) + 1);
|
||||
|
||||
/* Read in the strings */
|
||||
entry->strings = (char *)alloca(entry->string_size);
|
||||
read_entry_strings(file_open(entry), entry);
|
||||
|
||||
if (!(entry->flags & E_DYNAMIC)) {
|
||||
/* Do text warnings based on a scan through the reloc info. */
|
||||
do_relocation_warnings(entry, 0, outfile, nlist_bitvector);
|
||||
|
||||
/* Do data warnings based on a scan through the reloc info. */
|
||||
do_relocation_warnings(entry, 1, outfile, nlist_bitvector);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan through all of the nlist entries in this file and pick up
|
||||
* anything that the scan through the relocation stuff didn't.
|
||||
*/
|
||||
text_scan = init_debug_scan(0, entry);
|
||||
data_scan = init_debug_scan(1, entry);
|
||||
|
||||
for (i = 0; i < nsym; i++) {
|
||||
struct nlist *np;
|
||||
symbol *g;
|
||||
|
||||
g = entry->symbols[i].symbol;
|
||||
np = &entry->symbols[i].nzlist.nlist;
|
||||
|
||||
if (g == NULL)
|
||||
continue;
|
||||
|
||||
if (!(np->n_type & N_EXT) && !SET_ELEMENT_P(np->n_type)) {
|
||||
warnx("internal error: `%s' N_EXT not set", g->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(g->flags & GS_REFERENCED)) {
|
||||
#if 0
|
||||
/* Check for undefined shobj symbols */
|
||||
struct localsymbol *lsp;
|
||||
register int type;
|
||||
|
||||
for (lsp = g->sorefs; lsp; lsp = lsp->next) {
|
||||
type = lsp->nzlist.nz_type;
|
||||
if ((type & N_EXT) &&
|
||||
type != (N_UNDF | N_EXT)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (type == (N_UNDF | N_EXT)) {
|
||||
fprintf(stderr,
|
||||
"Undefined symbol %s referenced from %s\n",
|
||||
g->name,
|
||||
get_file_name(entry));
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
dont_allow_symbol_name = 0;
|
||||
|
||||
if (list_multiple_defs && g->mult_defs) {
|
||||
|
||||
errfmt = "Definition of symbol `%s' (multiply defined)";
|
||||
switch (np->n_type) {
|
||||
case N_TEXT | N_EXT:
|
||||
line_number =
|
||||
address_to_line(np->n_value, text_scan);
|
||||
file_name = text_scan[0].filename;
|
||||
break;
|
||||
|
||||
case N_DATA | N_EXT:
|
||||
line_number =
|
||||
address_to_line(np->n_value, data_scan);
|
||||
file_name = data_scan[0].filename;
|
||||
break;
|
||||
|
||||
case N_SETA | N_EXT:
|
||||
case N_SETT | N_EXT:
|
||||
case N_SETD | N_EXT:
|
||||
case N_SETB | N_EXT:
|
||||
if (g->mult_defs == 2)
|
||||
continue;
|
||||
errfmt =
|
||||
"First set element definition of symbol `%s' (multiply defined)";
|
||||
line_number = -1;
|
||||
break;
|
||||
|
||||
case N_SIZE | N_EXT:
|
||||
errfmt =
|
||||
"Size element definition of symbol `%s' (multiply defined)";
|
||||
line_number = -1;
|
||||
break;
|
||||
|
||||
case N_INDR | N_EXT:
|
||||
errfmt =
|
||||
"Alias definition of symbol `%s' (multiply defined)";
|
||||
line_number = -1;
|
||||
break;
|
||||
|
||||
case N_UNDF | N_EXT:
|
||||
/* Don't print out multiple defs at references.*/
|
||||
continue;
|
||||
|
||||
default:
|
||||
warnx("%s: unexpected multiple definitions "
|
||||
"of symbol `%s', type %#x",
|
||||
get_file_name(entry),
|
||||
g->name, np->n_type);
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (BIT_SET_P(nlist_bitvector, i)) {
|
||||
continue;
|
||||
} else if (list_unresolved_refs &&
|
||||
!g->defined && !g->so_defined) {
|
||||
|
||||
if (g->undef_refs == 0)
|
||||
reported_undefineds++;
|
||||
if (g->undef_refs >= MAX_UREFS_PRINTED)
|
||||
continue;
|
||||
if (++(g->undef_refs) == MAX_UREFS_PRINTED)
|
||||
errfmt = "More undefined `%s' refs follow";
|
||||
else
|
||||
errfmt = "Undefined symbol `%s' referenced";
|
||||
line_number = -1;
|
||||
} else if (g->def_lsp && g->def_lsp->entry != entry &&
|
||||
!(entry->flags & E_DYNAMIC) &&
|
||||
g->def_lsp->entry->flags & E_SECONDCLASS) {
|
||||
fprintf(outfile,
|
||||
"%s: Undefined symbol `%s' referenced (use %s ?)\n",
|
||||
get_file_name(entry),
|
||||
g->name,
|
||||
g->def_lsp->entry->local_sym_name);
|
||||
continue;
|
||||
} else if (g->warning) {
|
||||
/*
|
||||
* There are two cases in which we don't want to do
|
||||
* this. The first is if this is a definition instead
|
||||
* of a reference. The second is if it's the reference
|
||||
* used by the warning stabs itself.
|
||||
*/
|
||||
if (np->n_type != (N_EXT | N_UNDF) ||
|
||||
(entry->symbols[i].flags & LS_WARNING))
|
||||
continue;
|
||||
|
||||
errfmt = g->warning;
|
||||
line_number = -1;
|
||||
dont_allow_symbol_name = 1;
|
||||
} else
|
||||
continue;
|
||||
|
||||
if (line_number == -1)
|
||||
fprintf(outfile, "%s: ", get_file_name(entry));
|
||||
else
|
||||
fprintf(outfile, "%s:%d: ", file_name, line_number);
|
||||
|
||||
if (dont_allow_symbol_name)
|
||||
fprintf(outfile, "%s", errfmt);
|
||||
else
|
||||
fprintf(outfile, errfmt, g->name);
|
||||
|
||||
fputc('\n', outfile);
|
||||
}
|
||||
free(text_scan);
|
||||
free(data_scan);
|
||||
entry->strings = 0; /* Since it will disappear anyway. */
|
||||
}
|
||||
|
||||
int
|
||||
do_warnings(outfile)
|
||||
FILE *outfile;
|
||||
{
|
||||
|
||||
list_unresolved_refs = !relocatable_output &&
|
||||
( (undefined_global_sym_count - undefined_weak_sym_count) > 0
|
||||
|| undefined_shobj_sym_count
|
||||
);
|
||||
list_multiple_defs = multiple_def_count != 0;
|
||||
|
||||
if (!(list_unresolved_refs ||
|
||||
list_warning_symbols ||
|
||||
list_multiple_defs))
|
||||
/* No need to run this routine */
|
||||
return 1;
|
||||
|
||||
if (entry_symbol && !entry_symbol->defined)
|
||||
fprintf(outfile, "Undefined entry symbol `%s'\n",
|
||||
entry_symbol->name);
|
||||
|
||||
each_file(do_file_warnings, (void *)outfile);
|
||||
|
||||
if (list_unresolved_refs &&
|
||||
reported_undefineds !=
|
||||
(undefined_global_sym_count - undefined_weak_sym_count))
|
||||
warnx("Spurious undefined symbols: "
|
||||
"# undefined symbols %d, reported %d",
|
||||
(undefined_global_sym_count - undefined_weak_sym_count),
|
||||
reported_undefineds);
|
||||
|
||||
if (list_unresolved_refs || list_multiple_defs)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1993 Paul Kranenburg
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Paul Kranenburg.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (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: xbits.c,v 1.4 1994/01/29 02:03:18 jtc Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* "Generic" byte-swap routines.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
#include <ar.h>
|
||||
#include <ranlib.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
void
|
||||
swap_longs(lp, n)
|
||||
int n;
|
||||
long *lp;
|
||||
{
|
||||
for (; n > 0; n--, lp++)
|
||||
*lp = md_swap_long(*lp);
|
||||
}
|
||||
|
||||
void
|
||||
swap_symbols(s, n)
|
||||
struct nlist *s;
|
||||
int n;
|
||||
{
|
||||
for (; n; n--, s++) {
|
||||
s->n_un.n_strx = md_swap_long(s->n_un.n_strx);
|
||||
s->n_desc = md_swap_short(s->n_desc);
|
||||
s->n_value = md_swap_long(s->n_value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
swap_zsymbols(s, n)
|
||||
struct nzlist *s;
|
||||
int n;
|
||||
{
|
||||
for (; n; n--, s++) {
|
||||
s->nz_strx = md_swap_long(s->nz_strx);
|
||||
s->nz_desc = md_swap_short(s->nz_desc);
|
||||
s->nz_value = md_swap_long(s->nz_value);
|
||||
s->nz_size = md_swap_long(s->nz_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
swap_ranlib_hdr(rlp, n)
|
||||
struct ranlib *rlp;
|
||||
int n;
|
||||
{
|
||||
for (; n; n--, rlp++) {
|
||||
rlp->ran_un.ran_strx = md_swap_long(rlp->ran_un.ran_strx);
|
||||
rlp->ran_off = md_swap_long(rlp->ran_off);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
swap__dynamic(dp)
|
||||
struct _dynamic *dp;
|
||||
{
|
||||
dp->d_version = md_swap_long(dp->d_version);
|
||||
dp->d_debug = (struct so_debug *)md_swap_long((long)dp->d_debug);
|
||||
dp->d_un.d_sdt = (struct section_dispatch_table *)
|
||||
md_swap_long((long)dp->d_un.d_sdt);
|
||||
dp->d_entry = (struct ld_entry *)md_swap_long((long)dp->d_entry);
|
||||
}
|
||||
|
||||
void
|
||||
swap_section_dispatch_table(sdp)
|
||||
struct section_dispatch_table *sdp;
|
||||
{
|
||||
swap_longs((long *)sdp, sizeof(*sdp)/sizeof(long));
|
||||
}
|
||||
|
||||
void
|
||||
swap_so_debug(ddp)
|
||||
struct so_debug *ddp;
|
||||
{
|
||||
swap_longs((long *)ddp, sizeof(*ddp)/sizeof(long));
|
||||
}
|
||||
|
||||
void
|
||||
swapin_sod(sodp, n)
|
||||
struct sod *sodp;
|
||||
int n;
|
||||
{
|
||||
unsigned long bits;
|
||||
|
||||
for (; n; n--, sodp++) {
|
||||
sodp->sod_name = md_swap_long(sodp->sod_name);
|
||||
sodp->sod_major = md_swap_short(sodp->sod_major);
|
||||
sodp->sod_minor = md_swap_short(sodp->sod_minor);
|
||||
sodp->sod_next = md_swap_long(sodp->sod_next);
|
||||
bits = ((unsigned long *)sodp)[1];
|
||||
sodp->sod_library = ((bits >> 24) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
swapout_sod(sodp, n)
|
||||
struct sod *sodp;
|
||||
int n;
|
||||
{
|
||||
unsigned long bits;
|
||||
|
||||
for (; n; n--, sodp++) {
|
||||
sodp->sod_name = md_swap_long(sodp->sod_name);
|
||||
sodp->sod_major = md_swap_short(sodp->sod_major);
|
||||
sodp->sod_minor = md_swap_short(sodp->sod_minor);
|
||||
sodp->sod_next = md_swap_long(sodp->sod_next);
|
||||
bits = (unsigned long)(sodp->sod_library) << 24;
|
||||
((unsigned long *)sodp)[1] = bits;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
swap_rrs_hash(fsp, n)
|
||||
struct rrs_hash *fsp;
|
||||
int n;
|
||||
{
|
||||
for (; n; n--, fsp++) {
|
||||
fsp->rh_symbolnum = md_swap_long(fsp->rh_symbolnum);
|
||||
fsp->rh_next = md_swap_long(fsp->rh_next);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
# $NetBSD: Makefile,v 1.15 1997/03/24 22:06:36 christos Exp $
|
||||
# $NetBSD: Makefile,v 1.16 1997/04/16 16:49:43 christos Exp $
|
||||
|
||||
PROG= ld.so
|
||||
SRCS= mdprologue.S rtld.c malloc.c shlib.c etc.c md.c vfprintf.c
|
||||
MAN= rtld.1
|
||||
LDDIR?= $(.CURDIR)/..
|
||||
PICFLAG=-fpic -fno-function-cse
|
||||
CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE_ARCH) $(PICFLAG) -DRTLD -DLIBC_SCCS
|
||||
CFLAGS+=$(PICFLAG) -DRTLD -DLIBC_SCCS
|
||||
ASFLAGS+=-k
|
||||
LDFLAGS+=-Bshareable -Bsymbolic -assert nosymbolic
|
||||
.if defined(DESTDIR)
|
||||
@ -19,7 +18,7 @@ MLINKS= rtld.1 ld.so.1
|
||||
INCS=${HDRS}
|
||||
INCSDIR=/usr/include
|
||||
|
||||
.PATH: $(LDDIR) $(LDDIR)/$(MACHINE_ARCH) ${.CURDIR}/../../../../lib/libc/stdio
|
||||
.PATH: ${.CURDIR}/../../../../lib/libc/stdio
|
||||
|
||||
$(PROG):
|
||||
$(LD) -o $(PROG) $(LDFLAGS) $(OBJS) $(LDADD)
|
||||
|
@ -1,13 +1,9 @@
|
||||
# $NetBSD: Makefile,v 1.10 1995/03/06 04:24:41 cgd Exp $
|
||||
# $NetBSD: Makefile,v 1.11 1997/04/16 16:49:42 christos Exp $
|
||||
|
||||
PROG= ldconfig
|
||||
SRCS= ldconfig.c shlib.c etc.c
|
||||
LDDIR?= $(.CURDIR)/..
|
||||
CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE_ARCH)
|
||||
LDSTATIC=-static
|
||||
BINDIR= /sbin
|
||||
MAN= ldconfig.8
|
||||
|
||||
.PATH: $(LDDIR) $(LDDIR)/$(MACHINE_ARCH)
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
Loading…
Reference in New Issue
Block a user