mirror of
https://github.com/freebsd/freebsd-src
synced 2024-07-21 18:27:22 +00:00
Imported NetBSD's ld for shared libs.
This commit is contained in:
parent
19bcb5e4a2
commit
b9ae52e32a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=696
|
@ -1,8 +1,15 @@
|
|||
# @(#)Makefile 6.2 (Berkeley) 4/30/91
|
||||
# $Id: Makefile,v 1.8 1993/11/03 13:01:36 cgd Exp $
|
||||
#
|
||||
|
||||
PROG= ld
|
||||
SRCS= ld.c cplus-dem.c
|
||||
NOMAN= noman
|
||||
LINKS= ${BINDIR}/ld ${BINDIR}/../libexec/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)
|
||||
|
||||
LDADD+= -lgnumalloc
|
||||
DPADD+= /usr/lib/libgnumalloc.a
|
||||
|
||||
SUBDIR= ldconfig ldd rtld
|
||||
|
||||
.PATH: $(.CURDIR)/$(MACHINE)
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)cplus-dem.c 5.4 (Berkeley) 4/30/91";
|
||||
/*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++
|
||||
|
|
211
gnu/usr.bin/ld/etc.c
Normal file
211
gnu/usr.bin/ld/etc.c
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* $Id: etc.c,v 1.2 1993/10/21 00:52:52 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.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"
|
||||
|
||||
/*
|
||||
* Report a nonfatal error.
|
||||
*/
|
||||
|
||||
void
|
||||
#if __STDC__
|
||||
error(char *fmt, ...)
|
||||
#else
|
||||
error(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
(void)fprintf(stderr, "%s: ", progname);
|
||||
(void)vfprintf(stderr, fmt, ap);
|
||||
(void)fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Report a fatal error.
|
||||
*/
|
||||
|
||||
void
|
||||
#if __STDC__
|
||||
fatal(char *fmt, ...)
|
||||
#else
|
||||
fatal(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
(void)fprintf(stderr, "%s: ", progname);
|
||||
(void)vfprintf(stderr, fmt, ap);
|
||||
(void)fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
|
||||
if (outdesc >= 0)
|
||||
unlink(output_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a newly-allocated string whose contents concatenate
|
||||
* the strings S1, S2, S3.
|
||||
*/
|
||||
|
||||
char *
|
||||
concat(s1, s2, s3)
|
||||
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;
|
||||
}
|
||||
|
||||
/* Parse the string ARG using scanf format FORMAT, and return the result.
|
||||
If it does not parse, report fatal error
|
||||
generating the error message using format string ERROR and ARG as arg. */
|
||||
|
||||
int
|
||||
parse(arg, format, error)
|
||||
char *arg, *format, *error;
|
||||
{
|
||||
int x;
|
||||
if (1 != sscanf (arg, format, &x))
|
||||
fatal (error, arg);
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Like malloc but get fatal error if memory is exhausted. */
|
||||
|
||||
void *
|
||||
xmalloc(size)
|
||||
int size;
|
||||
{
|
||||
register void *result = (void *)malloc (size);
|
||||
|
||||
if (!result)
|
||||
fatal ("virtual memory exhausted", 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Like realloc but get fatal error if memory is exhausted. */
|
||||
|
||||
void *
|
||||
xrealloc(ptr, size)
|
||||
void *ptr;
|
||||
int size;
|
||||
{
|
||||
register void *result;
|
||||
|
||||
if (ptr == NULL)
|
||||
result = (void *)malloc (size);
|
||||
else
|
||||
result = (void *)realloc (ptr, size);
|
||||
|
||||
if (!result)
|
||||
fatal ("virtual memory exhausted", 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USG
|
||||
void
|
||||
bzero(p, n)
|
||||
char *p;
|
||||
{
|
||||
memset (p, 0, n);
|
||||
}
|
||||
|
||||
void
|
||||
bcopy(from, to, n)
|
||||
char *from, *to;
|
||||
{
|
||||
memcpy (to, from, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* These must move */
|
||||
|
||||
#ifndef RTLD
|
||||
/*
|
||||
* Output COUNT*ELTSIZE bytes of data at BUF to the descriptor DESC.
|
||||
*/
|
||||
void
|
||||
mywrite (buf, count, eltsize, desc)
|
||||
char *buf;
|
||||
int count;
|
||||
int eltsize;
|
||||
int desc;
|
||||
{
|
||||
register int val;
|
||||
register int bytes = count * eltsize;
|
||||
|
||||
while (bytes > 0) {
|
||||
val = write (desc, buf, bytes);
|
||||
if (val <= 0)
|
||||
perror(output_filename);
|
||||
buf += val;
|
||||
bytes -= val;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output PADDING zero-bytes to descriptor OUTDESC.
|
||||
PADDING may be negative; in that case, do nothing. */
|
||||
|
||||
void
|
||||
padfile (padding, outdesc)
|
||||
int padding;
|
||||
int outdesc;
|
||||
{
|
||||
register char *buf;
|
||||
if (padding <= 0)
|
||||
return;
|
||||
|
||||
buf = (char *) alloca (padding);
|
||||
bzero (buf, padding);
|
||||
mywrite (buf, padding, 1, outdesc);
|
||||
}
|
||||
#endif
|
15
gnu/usr.bin/ld/i386/md-static-funcs.c
Normal file
15
gnu/usr.bin/ld/i386/md-static-funcs.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
/*
|
||||
* Called by ld.so when onanating.
|
||||
* This *must* be a static function, so it is not called through a jmpslot.
|
||||
*/
|
||||
static void
|
||||
md_relocate_simple(r, relocation, addr)
|
||||
struct relocation_info *r;
|
||||
long relocation;
|
||||
char *addr;
|
||||
{
|
||||
if (r->r_relative)
|
||||
*(long *)addr += relocation;
|
||||
}
|
||||
|
329
gnu/usr.bin/ld/i386/md.c
Normal file
329
gnu/usr.bin/ld/i386/md.c
Normal file
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* 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 withough 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: md.c,v 1.2 1993/10/27 00:54:58 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
/*
|
||||
* Get relocation addend corresponding to relocation record RP
|
||||
* from address ADDR
|
||||
*/
|
||||
long
|
||||
md_get_addend(rp, addr)
|
||||
struct relocation_info *rp;
|
||||
unsigned char *addr;
|
||||
{
|
||||
switch (RELOC_TARGET_SIZE(rp)) {
|
||||
case 0:
|
||||
return get_byte(addr);
|
||||
break;
|
||||
case 1:
|
||||
return get_short(addr);
|
||||
break;
|
||||
case 2:
|
||||
return get_long(addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Put RELOCATION at ADDR according to relocation record RP.
|
||||
*/
|
||||
void
|
||||
md_relocate(rp, relocation, addr, relocatable_output)
|
||||
struct relocation_info *rp;
|
||||
long relocation;
|
||||
unsigned char *addr;
|
||||
{
|
||||
switch (RELOC_TARGET_SIZE(rp)) {
|
||||
case 0:
|
||||
put_byte(addr, relocation);
|
||||
break;
|
||||
case 1:
|
||||
put_short(addr, relocation);
|
||||
break;
|
||||
case 2:
|
||||
put_long(addr, relocation);
|
||||
break;
|
||||
default:
|
||||
fatal("Unsupported relocation size: %x", RELOC_TARGET_SIZE(rp));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize (output) exec header such that useful values are
|
||||
* obtained from subsequent N_*() macro evaluations.
|
||||
*/
|
||||
void
|
||||
md_init_header(hp, magic, flags)
|
||||
struct exec *hp;
|
||||
int magic, flags;
|
||||
{
|
||||
N_SETMAGIC((*hp), magic, MID_I386, flags);
|
||||
|
||||
/* TEXT_START depends on the value of outheader.a_entry. */
|
||||
if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */
|
||||
hp->a_entry = PAGSIZ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Machine dependent part of claim_rrs_reloc().
|
||||
* Set RRS relocation type.
|
||||
*/
|
||||
int
|
||||
md_make_reloc(rp, r, type)
|
||||
struct relocation_info *rp, *r;
|
||||
int type;
|
||||
{
|
||||
/* Relocation size */
|
||||
r->r_length = rp->r_length;
|
||||
|
||||
if (RELOC_PCREL_P(rp))
|
||||
r->r_pcrel = 1;
|
||||
|
||||
if (type & RELTYPE_RELATIVE)
|
||||
r->r_relative = 1;
|
||||
|
||||
if (type & RELTYPE_COPY)
|
||||
r->r_copy = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
|
||||
* to the binder slot (which is at offset 0 of the PLT).
|
||||
*/
|
||||
void
|
||||
md_make_jmpslot(sp, offset, index)
|
||||
jmpslot_t *sp;
|
||||
long offset;
|
||||
long index;
|
||||
{
|
||||
/*
|
||||
* i386 PC-relative "fixed point" is located right after the
|
||||
* instruction it pertains to.
|
||||
*/
|
||||
u_long fudge = - (sizeof(sp->opcode) + sizeof(sp->addr) + offset);
|
||||
|
||||
sp->opcode = CALL;
|
||||
#if 0
|
||||
sp->addr = fudge;
|
||||
#else
|
||||
sp->addr[0] = fudge & 0xffff;
|
||||
sp->addr[1] = fudge >> 16;
|
||||
#endif
|
||||
sp->reloc_index = index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a "direct" transfer (ie. not through the run-time binder) from
|
||||
* jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
|
||||
* and by `ld.so' after resolving the symbol.
|
||||
* On the i386, we use the JMP instruction which is PC relative, so no
|
||||
* further RRS relocations will be necessary for such a jmpslot.
|
||||
*/
|
||||
void
|
||||
md_fix_jmpslot(sp, offset, addr)
|
||||
jmpslot_t *sp;
|
||||
long offset;
|
||||
u_long addr;
|
||||
{
|
||||
u_long fudge = addr - (sizeof(sp->opcode) + sizeof(sp->addr) + offset);
|
||||
|
||||
sp->opcode = JUMP;
|
||||
#if 0
|
||||
sp->addr = fudge;
|
||||
#else
|
||||
sp->addr[0] = fudge & 0xffff;
|
||||
sp->addr[1] = fudge >> 16;
|
||||
#endif
|
||||
sp->reloc_index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the relocation record for a RRS jmpslot.
|
||||
*/
|
||||
void
|
||||
md_make_jmpreloc(rp, r, type)
|
||||
struct relocation_info *rp, *r;
|
||||
int type;
|
||||
{
|
||||
jmpslot_t *sp;
|
||||
|
||||
/*
|
||||
* Fix relocation address to point to the correct
|
||||
* location within this jmpslot.
|
||||
*/
|
||||
r->r_address += sizeof(sp->opcode);
|
||||
|
||||
/* Relocation size */
|
||||
r->r_length = 2;
|
||||
|
||||
/* Set relocation type */
|
||||
r->r_jmptable = 1;
|
||||
if (type & RELTYPE_RELATIVE)
|
||||
r->r_relative = 1;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Set relocation type for a RRS GOT relocation.
|
||||
*/
|
||||
void
|
||||
md_make_gotreloc(rp, r, type)
|
||||
struct relocation_info *rp, *r;
|
||||
int type;
|
||||
{
|
||||
r->r_baserel = 1;
|
||||
if (type & RELTYPE_RELATIVE)
|
||||
r->r_relative = 1;
|
||||
|
||||
/* Relocation size */
|
||||
r->r_length = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set relocation type for a RRS copy operation.
|
||||
*/
|
||||
void
|
||||
md_make_cpyreloc(rp, r)
|
||||
struct relocation_info *rp, *r;
|
||||
{
|
||||
/* Relocation size */
|
||||
r->r_length = 2;
|
||||
|
||||
r->r_copy = 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef NEED_SWAP
|
||||
|
||||
/*
|
||||
* Byte swap routines for cross-linking.
|
||||
*/
|
||||
|
||||
void
|
||||
md_swapin_exec_hdr(h)
|
||||
struct exec *h;
|
||||
{
|
||||
int skip = 0;
|
||||
|
||||
if (!N_BADMAG(*h))
|
||||
skip = 1;
|
||||
|
||||
swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
|
||||
}
|
||||
|
||||
void
|
||||
md_swapout_exec_hdr(h)
|
||||
struct exec *h;
|
||||
{
|
||||
/* NetBSD: Always leave magic alone */
|
||||
int skip = 1;
|
||||
#if 0
|
||||
if (N_GETMAGIC(*h) == OMAGIC)
|
||||
skip = 0;
|
||||
#endif
|
||||
|
||||
swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
md_swapin_reloc(r, n)
|
||||
struct relocation_info *r;
|
||||
int n;
|
||||
{
|
||||
int bits;
|
||||
|
||||
for (; n; n--, r++) {
|
||||
r->r_address = md_swap_long(r->r_address);
|
||||
bits = ((int *)r)[1];
|
||||
r->r_symbolnum = md_swap_long(bits & 0xffffff00);
|
||||
r->r_pcrel = (bits & 1);
|
||||
r->r_length = ((bits >> 1) & 3);
|
||||
r->r_extern = ((bits >> 3) & 1);
|
||||
r->r_baserel = ((bits >> 4) & 1);
|
||||
r->r_jmptable = ((bits >> 5) & 1);
|
||||
r->r_relative = ((bits >> 6) & 1);
|
||||
#ifdef N_SIZE
|
||||
r->r_copy = ((bits >> 7) & 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
md_swapout_reloc(r, n)
|
||||
struct relocation_info *r;
|
||||
int n;
|
||||
{
|
||||
int bits;
|
||||
|
||||
for (; n; n--, r++) {
|
||||
r->r_address = md_swap_long(r->r_address);
|
||||
bits = (md_swap_long(r->r_symbolnum) & 0xffffff00);
|
||||
bits |= (r->r_pcrel & 1);
|
||||
bits |= ((r->r_length << 1) & 6);
|
||||
bits |= ((r->r_extern << 3) & 8);
|
||||
bits |= ((r->r_baserel << 4) & 0x10);
|
||||
bits |= ((r->r_jmptable << 5) & 0x20);
|
||||
bits |= ((r->r_relative << 6) & 0x40);
|
||||
#ifdef N_SIZE
|
||||
bits |= ((r->r_copy << 7) & 0x80);
|
||||
#endif
|
||||
((int *)r)[1] = bits;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
md_swapout_jmpslot(j, n)
|
||||
jmpslot_t *j;
|
||||
int n;
|
||||
{
|
||||
for (; n; n--, j++) {
|
||||
j->opcode = md_swap_short(j->opcode);
|
||||
j->addr[0] = md_swap_short(j->addr[0]);
|
||||
j->addr[1] = md_swap_short(j->addr[1]);
|
||||
j->reloc_index = md_swap_short(j->reloc_index);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NEED_SWAP */
|
198
gnu/usr.bin/ld/i386/md.h
Normal file
198
gnu/usr.bin/ld/i386/md.h
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* $Id: md.h,v 1.3 1993/10/24 00:52:40 pk Exp $ - I386 dependent definitions
|
||||
*/
|
||||
|
||||
|
||||
#if defined(CROSS_LINKER) && defined(XHOST) && XHOST==sparc
|
||||
|
||||
#define NEED_SWAP
|
||||
|
||||
#endif
|
||||
|
||||
#define MAX_ALIGNMENT (sizeof (long))
|
||||
|
||||
#ifdef NetBSD
|
||||
#define PAGSIZ __LDPGSZ
|
||||
#else
|
||||
#define PAGSIZ 4096
|
||||
#endif
|
||||
|
||||
#define N_SET_FLAG(ex,f) N_SETMAGIC(ex,N_GETMAGIC(ex), MID_MACHINE, \
|
||||
N_GETFLAG(ex)|(f))
|
||||
|
||||
#define N_IS_DYNAMIC(ex) ((N_GETFLAG(ex) & EX_DYNAMIC))
|
||||
|
||||
/*
|
||||
* Should be handled by a.out.h ?
|
||||
*/
|
||||
#define N_ADJUST(ex) (((ex).a_entry < PAGSIZ) ? -PAGSIZ : 0)
|
||||
#define TEXT_START(ex) (N_TXTADDR(ex) + N_ADJUST(ex))
|
||||
#define DATA_START(ex) (N_DATADDR(ex) + N_ADJUST(ex))
|
||||
|
||||
#define RELOC_STATICS_THROUGH_GOT_P(r) (0)
|
||||
#define JMPSLOT_NEEDS_RELOC (0)
|
||||
|
||||
#define md_got_reloc(r) (0)
|
||||
|
||||
#define md_get_rt_segment_addend(r,a) md_get_addend(r,a)
|
||||
|
||||
/* Width of a Global Offset Table entry */
|
||||
#define GOT_ENTRY_SIZE 4
|
||||
typedef long got_t;
|
||||
|
||||
typedef struct jmpslot {
|
||||
u_short opcode;
|
||||
u_short addr[2];
|
||||
u_short reloc_index;
|
||||
#define JMPSLOT_RELOC_MASK 0xffff
|
||||
} jmpslot_t;
|
||||
|
||||
#define NOP 0x90
|
||||
#define CALL 0xe890 /* NOP + CALL opcode */
|
||||
#define JUMP 0xe990 /* NOP + JMP opcode */
|
||||
#define TRAP 0xcc /* INT 3 */
|
||||
|
||||
/*
|
||||
* Byte swap defs for cross linking
|
||||
*/
|
||||
|
||||
#if !defined(NEED_SWAP)
|
||||
|
||||
#define md_swapin_exec_hdr(h)
|
||||
#define md_swapout_exec_hdr(h)
|
||||
#define md_swapin_symbols(s,n)
|
||||
#define md_swapout_symbols(s,n)
|
||||
#define md_swapin_zsymbols(s,n)
|
||||
#define md_swapout_zsymbols(s,n)
|
||||
#define md_swapin_reloc(r,n)
|
||||
#define md_swapout_reloc(r,n)
|
||||
#define md_swapin_link_dynamic(l)
|
||||
#define md_swapout_link_dynamic(l)
|
||||
#define md_swapin_link_dynamic_2(l)
|
||||
#define md_swapout_link_dynamic_2(l)
|
||||
#define md_swapin_ld_debug(d)
|
||||
#define md_swapout_ld_debug(d)
|
||||
#define md_swapin_rrs_hash(f,n)
|
||||
#define md_swapout_rrs_hash(f,n)
|
||||
#define md_swapin_link_object(l,n)
|
||||
#define md_swapout_link_object(l,n)
|
||||
#define md_swapout_jmpslot(j,n)
|
||||
#define md_swapout_got(g,n)
|
||||
#define md_swapin_ranlib_hdr(h,n)
|
||||
#define md_swapout_ranlib_hdr(h,n)
|
||||
|
||||
#endif /* NEED_SWAP */
|
||||
|
||||
#ifdef CROSS_LINKER
|
||||
|
||||
#ifdef NEED_SWAP
|
||||
|
||||
/* Define IO byte swapping routines */
|
||||
|
||||
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));
|
||||
|
||||
#define md_swapin_symbols(s,n) swap_symbols(s,n)
|
||||
#define md_swapout_symbols(s,n) swap_symbols(s,n)
|
||||
#define md_swapin_zsymbols(s,n) swap_zsymbols(s,n)
|
||||
#define md_swapout_zsymbols(s,n) swap_zsymbols(s,n)
|
||||
#define md_swapin_link_dynamic(l) swap_link_dynamic(l)
|
||||
#define md_swapout_link_dynamic(l) swap_link_dynamic(l)
|
||||
#define md_swapin_link_dynamic_2(l) swap_link_dynamic_2(l)
|
||||
#define md_swapout_link_dynamic_2(l) swap_link_dynamic_2(l)
|
||||
#define md_swapin_ld_debug(d) swap_ld_debug(d)
|
||||
#define md_swapout_ld_debug(d) swap_ld_debug(d)
|
||||
#define md_swapin_rrs_hash(f,n) swap_rrs_hash(f,n)
|
||||
#define md_swapout_rrs_hash(f,n) swap_rrs_hash(f,n)
|
||||
#define md_swapin_link_object(l,n) swapin_link_object(l,n)
|
||||
#define md_swapout_link_object(l,n) swapout_link_object(l,n)
|
||||
#define md_swapout_got(g,n) swap_longs((long*)(g),n)
|
||||
#define md_swapin_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
|
||||
#define md_swapout_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
|
||||
|
||||
#define md_swap_short(x) ( (((x) >> 8) & 0xff) | (((x) & 0xff) << 8) )
|
||||
|
||||
#define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \
|
||||
(((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000))
|
||||
|
||||
#define get_byte(p) ( ((unsigned char *)(p))[0] )
|
||||
|
||||
#define get_short(p) ( ( ((unsigned char *)(p))[1] << 8) | \
|
||||
( ((unsigned char *)(p))[0] ) \
|
||||
)
|
||||
#define get_long(p) ( ( ((unsigned char *)(p))[3] << 24) | \
|
||||
( ((unsigned char *)(p))[2] << 16) | \
|
||||
( ((unsigned char *)(p))[1] << 8 ) | \
|
||||
( ((unsigned char *)(p))[0] ) \
|
||||
)
|
||||
|
||||
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
|
||||
|
||||
#define put_short(p, v) { ((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#define put_long(p, v) { ((unsigned char *)(p))[3] = \
|
||||
((((unsigned long)(v)) >> 24) & 0xff); \
|
||||
((unsigned char *)(p))[2] = \
|
||||
((((unsigned long)(v)) >> 16) & 0xff); \
|
||||
((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#else /* We need not swap, but must pay attention to alignment: */
|
||||
|
||||
#define md_swap_short(x) (x)
|
||||
#define md_swap_long(x) (x)
|
||||
|
||||
#define get_byte(p) ( ((unsigned char *)(p))[0] )
|
||||
|
||||
#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \
|
||||
( ((unsigned char *)(p))[1] ) \
|
||||
)
|
||||
|
||||
#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \
|
||||
( ((unsigned char *)(p))[1] << 16) | \
|
||||
( ((unsigned char *)(p))[2] << 8 ) | \
|
||||
( ((unsigned char *)(p))[3] ) \
|
||||
)
|
||||
|
||||
|
||||
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
|
||||
|
||||
#define put_short(p, v) { ((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#define put_long(p, v) { ((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) >> 24) & 0xff); \
|
||||
((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) >> 16) & 0xff); \
|
||||
((unsigned char *)(p))[2] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[3] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#endif /* NEED_SWAP */
|
||||
|
||||
#else /* Not a cross linker: use native */
|
||||
|
||||
#define md_swap_short(x) (x)
|
||||
#define md_swap_long(x) (x)
|
||||
|
||||
#define get_byte(where) (*(char *)(where))
|
||||
#define get_short(where) (*(short *)(where))
|
||||
#define get_long(where) (*(long *)(where))
|
||||
|
||||
#define put_byte(where,what) (*(char *)(where) = (what))
|
||||
#define put_short(where,what) (*(short *)(where) = (what))
|
||||
#define put_long(where,what) (*(long *)(where) = (what))
|
||||
|
||||
#endif /* CROSS_LINKER */
|
||||
|
124
gnu/usr.bin/ld/i386/mdprologue.S
Normal file
124
gnu/usr.bin/ld/i386/mdprologue.S
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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 withough 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: mdprologue.S,v 1.1 1993/10/16 21:53:16 pk Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* i386 run-time link editor entry points.
|
||||
*/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#define LCALL(x,y) .byte 0x9a ; .long y; .word x
|
||||
|
||||
.text
|
||||
.globl _binder, _binder_entry
|
||||
|
||||
/*
|
||||
* _rtl(int version, struct crt_ldso *crtp)
|
||||
*/
|
||||
#define FRAME 12 /* Size of stack frame */
|
||||
|
||||
|
||||
_rtl: # crt0 calls us here
|
||||
pushl %ebp # Allocate stack frame
|
||||
movl %esp, %ebp
|
||||
subl $FRAME, %esp
|
||||
pushl %ebx
|
||||
call 1f # PIC function prologue
|
||||
1:
|
||||
popl %ebx
|
||||
addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
|
||||
|
||||
movl 12(%ebp), %eax # Extract data from interface structure
|
||||
movl (%eax),%eax # base address of ld.so (first field)
|
||||
# setup arguments for rtld()
|
||||
movl (%ebx), %ecx # 1st entry in GOT is our __DYNAMIC
|
||||
addl %eax, %ecx # add load address
|
||||
pushl %ecx # 3rd arg
|
||||
pushl 12(%ebp) # 2nd arg == &crt.
|
||||
pushl 8(%ebp) # 1st arg == version
|
||||
addl _rtld@GOT(%ebx), %eax # relocate address of function
|
||||
call %eax # _rtld(version, crtp, DYNAMIC)
|
||||
addl $12,%esp # pop arguments
|
||||
|
||||
movl (-FRAME-4)(%ebp), %ebx # restore %ebx
|
||||
leave # remove stack frame,
|
||||
ret # let's rock
|
||||
|
||||
# First call to a procedure generally comes through here for
|
||||
# binding.
|
||||
|
||||
_binder_entry:
|
||||
pushl %ebp # setup a stack frame
|
||||
movl %esp, %ebp
|
||||
pusha # save all regs
|
||||
|
||||
movl $0, %eax # clear
|
||||
movl 4(%ebp), %esi # return address in PLT
|
||||
movw (%esi), %ax # get hold of relocation number
|
||||
subl $6, %esi # make it point to the jmpslot
|
||||
|
||||
pushl %eax # pushd arguments
|
||||
pushl %esi #
|
||||
call _binder@PLT # _binder(rpc, index)
|
||||
addl $8, %esp # pop arguments
|
||||
movl %eax, 4(%ebp) # return value from _binder() == actual
|
||||
# address of function
|
||||
popa # restore regs
|
||||
leave # remove our stack frame
|
||||
ret
|
||||
|
||||
# Special system call stubs which return real and effective user and group
|
||||
# id's. Saves overhead of making separate calls for each.
|
||||
# !! Relies on compatability option in BSD 4.three-and-a-half
|
||||
|
||||
.globl _getreuid, _getregid
|
||||
_getreuid:
|
||||
lea SYS_getuid, %eax
|
||||
LCALL(7,0)
|
||||
jc out
|
||||
movl 4(%esp), %ecx # get 1st arg
|
||||
movl %eax, (%ecx) # put value in it
|
||||
movl 8(%esp), %ecx # same for 2nd arg
|
||||
movl %edx, (%ecx) #
|
||||
ret # done
|
||||
|
||||
_getregid:
|
||||
lea SYS_getgid, %eax
|
||||
LCALL(7,0)
|
||||
jc out
|
||||
movl 4(%esp), %ecx # get 1st arg
|
||||
movl %eax, (%ecx) # put value in it
|
||||
movl 8(%esp), %ecx # same for 2nd arg
|
||||
movl %edx, (%ecx) #
|
||||
ret # done
|
||||
|
||||
out: jmp cerror@PLT # Call common error routine
|
||||
|
192
gnu/usr.bin/ld/ld.1
Normal file
192
gnu/usr.bin/ld/ld.1
Normal file
|
@ -0,0 +1,192 @@
|
|||
.\"
|
||||
.\" 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 withough 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.3 1993/11/02 22:56:51 pk Exp $
|
||||
.\"
|
||||
.Dd October 14, 1993
|
||||
.Dt LD 8
|
||||
.Os NetBSD 0.9
|
||||
.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 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 Ar library-specifier
|
||||
.Op Fl L Ar library-search-path
|
||||
.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 the symbol-file is taken as a base for link-editing the object files
|
||||
on the command line.
|
||||
.It \-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 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 (see the
|
||||
.Ar l
|
||||
option) 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 -Bstatic.
|
||||
.It Fl B Ar static
|
||||
The counterpart of -Bdynamic. This options turns off dynamic linking for
|
||||
all library specifiers until a -Bdynamic 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 Ar shareable
|
||||
Instructs the linker to build a shared object from the object files rather
|
||||
than a normal executable image.
|
||||
.It Fl B 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 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 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 Ar path
|
||||
Add
|
||||
.Ar path
|
||||
to the list of directories to search for libraries specified with the
|
||||
.Ar -l
|
||||
option.
|
||||
.It Fl l Ar lib-spec
|
||||
This option specifies a library to be considered for inclusion in the
|
||||
output. If the -Bdynamic option is in effect, a shared library of the
|
||||
form lib<spec>.so.m.n (where
|
||||
.Em m
|
||||
is the major, and
|
||||
.Em n
|
||||
is the minor version number, respectively) 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 -Bstatic options is in effect,
|
||||
an archive of the form lib<spec>.a is looked for in the library seach path.
|
||||
.It Fl M
|
||||
Produce output about the mapping of segments of the input files and the
|
||||
values assigned to (global) symbols in the output file.
|
||||
.It Fl N
|
||||
Produce a OMAGIC output file.
|
||||
.It Fl n
|
||||
Produce a NMAGIC output file.
|
||||
.It Fl o Ar filename
|
||||
Specifies the name of the output file. Defaults to
|
||||
.Dq a.out.
|
||||
.It Fl r
|
||||
Produce relocatable object file, suitable for another pass through
|
||||
.Nm ld.
|
||||
.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 (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 symbol
|
||||
Trace the manipulations inflicted on
|
||||
.Ar symbol
|
||||
.It Fl z
|
||||
Make a ZMAGIC output file. This is the default.
|
||||
.Sh FILES
|
||||
.Sh SEE ALSO
|
||||
.Xr ldconfig 1 ,
|
||||
.Xr link 5
|
||||
.Sh BUGS
|
||||
Spurious
|
||||
.Dq undefined symbols errors
|
||||
may be reported for symbols originating in shared libraries. This occurs
|
||||
when there is also at least one genuine undefined symbol to report.
|
||||
.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 HISTORY
|
||||
The shared library model employed by
|
||||
.Nm ld
|
||||
appeared first in SunOS 4.0
|
192
gnu/usr.bin/ld/ld.1aout
Normal file
192
gnu/usr.bin/ld/ld.1aout
Normal file
|
@ -0,0 +1,192 @@
|
|||
.\"
|
||||
.\" 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 withough 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.3 1993/11/02 22:56:51 pk Exp $
|
||||
.\"
|
||||
.Dd October 14, 1993
|
||||
.Dt LD 8
|
||||
.Os NetBSD 0.9
|
||||
.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 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 Ar library-specifier
|
||||
.Op Fl L Ar library-search-path
|
||||
.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 the symbol-file is taken as a base for link-editing the object files
|
||||
on the command line.
|
||||
.It \-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 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 (see the
|
||||
.Ar l
|
||||
option) 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 -Bstatic.
|
||||
.It Fl B Ar static
|
||||
The counterpart of -Bdynamic. This options turns off dynamic linking for
|
||||
all library specifiers until a -Bdynamic 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 Ar shareable
|
||||
Instructs the linker to build a shared object from the object files rather
|
||||
than a normal executable image.
|
||||
.It Fl B 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 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 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 Ar path
|
||||
Add
|
||||
.Ar path
|
||||
to the list of directories to search for libraries specified with the
|
||||
.Ar -l
|
||||
option.
|
||||
.It Fl l Ar lib-spec
|
||||
This option specifies a library to be considered for inclusion in the
|
||||
output. If the -Bdynamic option is in effect, a shared library of the
|
||||
form lib<spec>.so.m.n (where
|
||||
.Em m
|
||||
is the major, and
|
||||
.Em n
|
||||
is the minor version number, respectively) 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 -Bstatic options is in effect,
|
||||
an archive of the form lib<spec>.a is looked for in the library seach path.
|
||||
.It Fl M
|
||||
Produce output about the mapping of segments of the input files and the
|
||||
values assigned to (global) symbols in the output file.
|
||||
.It Fl N
|
||||
Produce a OMAGIC output file.
|
||||
.It Fl n
|
||||
Produce a NMAGIC output file.
|
||||
.It Fl o Ar filename
|
||||
Specifies the name of the output file. Defaults to
|
||||
.Dq a.out.
|
||||
.It Fl r
|
||||
Produce relocatable object file, suitable for another pass through
|
||||
.Nm ld.
|
||||
.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 (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 symbol
|
||||
Trace the manipulations inflicted on
|
||||
.Ar symbol
|
||||
.It Fl z
|
||||
Make a ZMAGIC output file. This is the default.
|
||||
.Sh FILES
|
||||
.Sh SEE ALSO
|
||||
.Xr ldconfig 1 ,
|
||||
.Xr link 5
|
||||
.Sh BUGS
|
||||
Spurious
|
||||
.Dq undefined symbols errors
|
||||
may be reported for symbols originating in shared libraries. This occurs
|
||||
when there is also at least one genuine undefined symbol to report.
|
||||
.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 HISTORY
|
||||
The shared library model employed by
|
||||
.Nm ld
|
||||
appeared first in SunOS 4.0
|
6522
gnu/usr.bin/ld/ld.c
6522
gnu/usr.bin/ld/ld.c
File diff suppressed because it is too large
Load diff
890
gnu/usr.bin/ld/ld.h
Normal file
890
gnu/usr.bin/ld/ld.h
Normal file
|
@ -0,0 +1,890 @@
|
|||
/* $Id: ld.h,v 1.4 1993/11/01 16:26:16 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
|
||||
|
||||
#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)
|
||||
|
||||
/* Size of a page; obtained from the operating system. */
|
||||
|
||||
int page_size;
|
||||
|
||||
/* Name this program was invoked by. */
|
||||
|
||||
char *progname;
|
||||
|
||||
/* System dependencies */
|
||||
|
||||
/* Define this to specify the default executable format. */
|
||||
|
||||
#ifndef DEFAULT_MAGIC
|
||||
#define DEFAULT_MAGIC ZMAGIC
|
||||
#endif
|
||||
|
||||
#ifdef QMAGIC
|
||||
int oldmagic;
|
||||
#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)
|
||||
|
||||
#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__ */
|
||||
|
||||
/* 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 {
|
||||
/* Pointer to next symbol in this symbol's hash bucket. */
|
||||
struct glosym *link;
|
||||
/* Name of this symbol. */
|
||||
char *name;
|
||||
/* Value of this symbol as a global symbol. */
|
||||
long value;
|
||||
/*
|
||||
* Chain of external 'nlist's in files for this symbol, both defs and
|
||||
* refs.
|
||||
*/
|
||||
struct localsymbol *refs;
|
||||
/*
|
||||
* Any warning message that might be associated with this symbol from
|
||||
* an N_WARNING symbol encountered.
|
||||
*/
|
||||
char *warning;
|
||||
/*
|
||||
* Nonzero means definitions of this symbol as common have been seen,
|
||||
* and the value here is the largest size specified by any of them.
|
||||
*/
|
||||
int max_common_size;
|
||||
/*
|
||||
* For relocatable_output, records the index of this global sym in
|
||||
* the symbol table to be written, with the first global sym given
|
||||
* index 0.
|
||||
*/
|
||||
int symbolnum;
|
||||
/*
|
||||
* For dynamically linked output, records the index in the RRS
|
||||
* symbol table.
|
||||
*/
|
||||
int rrs_symbolnum;
|
||||
/*
|
||||
* Nonzero means a definition of this global symbol is known to
|
||||
* exist. Library members should not be loaded on its account.
|
||||
*/
|
||||
char defined;
|
||||
/*
|
||||
* Nonzero means a reference to this global symbol has been seen in a
|
||||
* file that is surely being loaded. A value higher than 1 is the
|
||||
* n_type code for the symbol's definition.
|
||||
*/
|
||||
char referenced;
|
||||
/*
|
||||
* A count of the number of undefined references printed for a
|
||||
* specific symbol. If a symbol is unresolved at the end of
|
||||
* digest_symbols (and the loading run is supposed to produce
|
||||
* relocatable output) do_file_warnings keeps track of how many
|
||||
* unresolved reference error messages have been printed for each
|
||||
* symbol here. When the number hits MAX_UREFS_PRINTED, messages
|
||||
* stop.
|
||||
*/
|
||||
unsigned char undef_refs;
|
||||
/*
|
||||
* 1 means that this symbol has multiple definitions. 2 means that
|
||||
* it has multiple definitions, and some of them are set elements,
|
||||
* one of which has been printed out already.
|
||||
*/
|
||||
unsigned char multiply_defined;
|
||||
/* Nonzero means print a message at all refs or defs of this symbol */
|
||||
char trace;
|
||||
|
||||
/*
|
||||
* For symbols of type N_INDR, this points at the real symbol.
|
||||
*/
|
||||
struct glosym *alias;
|
||||
|
||||
/*
|
||||
* Count number of elements in set vector if symbol is of type N_SETV
|
||||
*/
|
||||
int setv_count;
|
||||
|
||||
/* Dynamic lib support */
|
||||
|
||||
/*
|
||||
* Nonzero means a definition of this global symbol has been found
|
||||
* in a shared object. These symbols do not go into the symbol
|
||||
* section of the resulting a.out file. They *do* go into the
|
||||
* dynamic link information segment.
|
||||
*/
|
||||
char so_defined;
|
||||
|
||||
/* Size of symbol as determined by N_SIZE 'nlist's in object files */
|
||||
int size;
|
||||
|
||||
/*
|
||||
* Chain of external 'nlist's in shared objects for this symbol, both
|
||||
* defs and refs.
|
||||
*/
|
||||
struct localsymbol *sorefs;
|
||||
|
||||
/* The offset into one of the RRS tables, -1 if not used */
|
||||
long jmpslot_offset;
|
||||
char jmpslot_claimed;
|
||||
|
||||
long gotslot_offset;
|
||||
char gotslot_claimed;
|
||||
|
||||
char cpyreloc_reserved;
|
||||
char cpyreloc_claimed;
|
||||
|
||||
/* The local symbol that gave this global symbol its definition */
|
||||
struct nlist *def_nlist;
|
||||
} symbol;
|
||||
|
||||
/* Number of buckets in symbol hash table */
|
||||
#define TABSIZE 1009
|
||||
|
||||
/* The symbol hash table: a vector of TABSIZE pointers to struct glosym. */
|
||||
symbol *symtab[TABSIZE];
|
||||
#define FOR_EACH_SYMBOL(i,sp) { \
|
||||
int i; \
|
||||
for (i = 0; i < TABSIZE; i++) { \
|
||||
register symbol *sp; \
|
||||
for (sp = symtab[i]; sp; sp = sp->link)
|
||||
|
||||
#define END_EACH_SYMBOL }}
|
||||
|
||||
/* Number of symbols in symbol hash table. */
|
||||
int num_hash_tab_syms;
|
||||
|
||||
/* Count the number of nlist entries that are for local symbols.
|
||||
This count and the three following counts
|
||||
are incremented as as symbols are entered in the symbol table. */
|
||||
int local_sym_count;
|
||||
|
||||
/* Count number of nlist entries that are for local symbols
|
||||
whose names don't start with L. */
|
||||
int non_L_local_sym_count;
|
||||
|
||||
/* Count the number of nlist entries for debugger info. */
|
||||
int debugger_sym_count;
|
||||
|
||||
/* Count the number of global symbols referenced and not defined. */
|
||||
int undefined_global_sym_count;
|
||||
|
||||
/* Count the number of symbols referenced from shared objects and not defined */
|
||||
int undefined_shobj_sym_count;
|
||||
|
||||
/* Count the number of global symbols multiply defined. */
|
||||
int multiple_def_count;
|
||||
|
||||
/* Count the number of defined global symbols.
|
||||
Each symbol is counted only once
|
||||
regardless of how many different nlist entries refer to it,
|
||||
since the output file will need only one nlist entry for it.
|
||||
This count is computed by `digest_symbols';
|
||||
it is undefined while symbols are being loaded. */
|
||||
int defined_global_sym_count;
|
||||
|
||||
/* Count the number of symbols defined through common declarations.
|
||||
This count is kept in symdef_library, linear_library, and
|
||||
enter_global_ref. It is incremented when the defined flag is set
|
||||
in a symbol because of a common definition, and decremented when
|
||||
the symbol is defined "for real" (ie. by something besides a common
|
||||
definition). */
|
||||
int common_defined_global_count;
|
||||
|
||||
/* Count the number of linker defined symbols.
|
||||
XXX - Currently, only __DYNAMIC and _G_O_T_ go here if required,
|
||||
perhaps _etext, _edata and _end should go here too */
|
||||
int special_sym_count;
|
||||
|
||||
/* Count number of aliased symbols */
|
||||
int global_alias_count;
|
||||
|
||||
/* Count number of set element type symbols and the number of separate
|
||||
vectors which these symbols will fit into */
|
||||
int set_symbol_count;
|
||||
int set_vector_count;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
struct string_list_element *set_element_prefixes;
|
||||
|
||||
/* Count the number of warning symbols encountered. */
|
||||
int warning_count;
|
||||
|
||||
/* 1 => write load map. */
|
||||
int write_map;
|
||||
|
||||
/* 1 => write relocation into output file so can re-input it later. */
|
||||
int relocatable_output;
|
||||
|
||||
/* Nonzero means ptr to symbol entry for symbol to use as start addr.
|
||||
-e sets this. */
|
||||
symbol *entry_symbol;
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
/* Name of this file. */
|
||||
char *filename;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* Describe the layout of the contents of the file */
|
||||
|
||||
/* The file's a.out header. */
|
||||
struct exec header;
|
||||
/* Offset in file of GDB symbol segment, or 0 if there is none. */
|
||||
int symseg_offset;
|
||||
|
||||
/* Describe data from the file loaded into core */
|
||||
|
||||
/*
|
||||
* Symbol table of the file.
|
||||
* We need access to the global symbol early, ie. before
|
||||
* symbols are asssigned there final values. gotslot_offset is
|
||||
* here because GOT entries may be generated for local symbols.
|
||||
*/
|
||||
struct localsymbol {
|
||||
struct nzlist nzlist;
|
||||
struct glosym *symbol;
|
||||
struct localsymbol *next;
|
||||
long gotslot_offset;
|
||||
char gotslot_claimed;
|
||||
} *symbols;
|
||||
|
||||
/* Number of symbols in above array. */
|
||||
int nsymbols;
|
||||
|
||||
/* Size in bytes of string table. */
|
||||
int string_size;
|
||||
|
||||
/*
|
||||
* Pointer to the string table. The string table is not kept in core
|
||||
* all the time, but when it is in core, its address is here.
|
||||
*/
|
||||
char *strings;
|
||||
|
||||
/* Offset of string table (normally N_STROFF() + 4) */
|
||||
int strings_offset;
|
||||
|
||||
/* Next two used only if `relocatable_output' or if needed for */
|
||||
/* output of undefined reference line numbers. */
|
||||
|
||||
/* Text reloc info saved by `write_text' for `coptxtrel'. */
|
||||
struct relocation_info *textrel;
|
||||
int ntextrel;
|
||||
|
||||
/* Data reloc info saved by `write_data' for `copdatrel'. */
|
||||
struct relocation_info *datarel;
|
||||
int ndatarel;
|
||||
|
||||
/* Relation of this file's segments to the output file */
|
||||
|
||||
/* Start of this file's text seg in the output file core image. */
|
||||
int text_start_address;
|
||||
|
||||
/* Start of this file's data seg in the output file core image. */
|
||||
int data_start_address;
|
||||
|
||||
/* Start of this file's bss seg in the output file core image. */
|
||||
int bss_start_address;
|
||||
/*
|
||||
* Offset in bytes in the output file symbol table of the first local
|
||||
* symbol for this file. Set by `write_file_symbols'.
|
||||
*/
|
||||
int local_syms_offset;
|
||||
|
||||
/* For library members only */
|
||||
|
||||
/* For a library, points to chain of entries for the library members. */
|
||||
struct file_entry *subfiles;
|
||||
|
||||
/*
|
||||
* For a library member, offset of the member within the archive.
|
||||
* Zero for files that are not library members.
|
||||
*/
|
||||
int starting_offset;
|
||||
|
||||
/* Size of contents of this file, if library member. */
|
||||
int total_size;
|
||||
|
||||
/* For library member, points to the library's own entry. */
|
||||
struct file_entry *superfile;
|
||||
|
||||
/* For library member, points to next entry for next member. */
|
||||
struct file_entry *chain;
|
||||
|
||||
/* 1 if file is a library. */
|
||||
char library_flag;
|
||||
|
||||
/* 1 if file's header has been read into this structure. */
|
||||
char header_read_flag;
|
||||
|
||||
/* 1 means search a set of directories for this file. */
|
||||
char search_dirs_flag;
|
||||
|
||||
/*
|
||||
* 1 means this is base file of incremental load. Do not load this
|
||||
* file's text or data. Also default text_start to after this file's
|
||||
* bss.
|
||||
*/
|
||||
char just_syms_flag;
|
||||
|
||||
/* 1 means search for dynamic libraries (dependent on -B switch) */
|
||||
char search_dynamic_flag;
|
||||
|
||||
/* version numbers of selected shared library */
|
||||
int lib_major, lib_minor;
|
||||
|
||||
/* This entry is a shared object */
|
||||
char is_dynamic;
|
||||
};
|
||||
|
||||
typedef struct localsymbol localsymbol_t;
|
||||
|
||||
/* Vector of entries for input files specified by arguments.
|
||||
These are all the input files except for members of specified libraries. */
|
||||
struct file_entry *file_table;
|
||||
|
||||
/* Length of that vector. */
|
||||
int number_of_files;
|
||||
|
||||
/* Current 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 */
|
||||
int link_mode;
|
||||
|
||||
/*
|
||||
* 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).
|
||||
*/
|
||||
|
||||
int rrs_section_type;
|
||||
#define RRS_NONE 0
|
||||
#define RRS_PARTIAL 1
|
||||
#define RRS_FULL 2
|
||||
|
||||
int rrs_text_size;
|
||||
int rrs_data_size;
|
||||
int rrs_text_start;
|
||||
int rrs_data_start;
|
||||
|
||||
/* Version number to put in __DYNAMIC (set by -V) */
|
||||
int soversion;
|
||||
|
||||
/* When loading the text and data, we can avoid doing a close
|
||||
and another open between members of the same library.
|
||||
|
||||
These two variables remember the file that is currently open.
|
||||
Both are zero if no file is open.
|
||||
|
||||
See `each_file' and `file_close'. */
|
||||
|
||||
struct file_entry *input_file;
|
||||
int input_desc;
|
||||
|
||||
/* The name of the file to write; "a.out" by default. */
|
||||
|
||||
char *output_filename;
|
||||
|
||||
/* Descriptor for writing that file with `mywrite'. */
|
||||
|
||||
int outdesc;
|
||||
|
||||
/* Header for that file (filled in by `write_header'). */
|
||||
|
||||
struct exec outheader;
|
||||
|
||||
/* The following are computed by `digest_symbols'. */
|
||||
|
||||
int text_size; /* total size of text of all input files. */
|
||||
int data_size; /* total size of data of all input files. */
|
||||
int bss_size; /* total size of bss of all input files. */
|
||||
int text_reloc_size; /* total size of text relocation of all input files. */
|
||||
int data_reloc_size; /* total size of data relocation of all input files. */
|
||||
|
||||
/* Relocation offsets set by perform_relocation(). Defined globaly here
|
||||
because some of the RRS routines need access to them */
|
||||
int text_relocation;
|
||||
int data_relocation;
|
||||
int bss_relocation;
|
||||
int pc_relocation;
|
||||
|
||||
/* Specifications of start and length of the area reserved at the end
|
||||
of the data segment for the set vectors. Computed in 'digest_symbols' */
|
||||
int set_sect_start;
|
||||
int set_sect_size;
|
||||
|
||||
/* Amount of cleared space to leave between the text and data segments. */
|
||||
int text_pad;
|
||||
|
||||
/* Amount of bss segment to include as part of the data segment. */
|
||||
int data_pad;
|
||||
|
||||
|
||||
/* Record most of the command options. */
|
||||
|
||||
/* Address we assume the text section will be loaded at.
|
||||
We relocate symbols and text and data for this, but we do not
|
||||
write any padding in the output file for it. */
|
||||
int text_start;
|
||||
|
||||
/* Offset of default entry-pc within the text section. */
|
||||
int entry_offset;
|
||||
|
||||
/* Address we decide the data section will be loaded at. */
|
||||
int data_start;
|
||||
int bss_start;
|
||||
|
||||
/* Keep a list of any symbols referenced from the command line (so
|
||||
that error messages for these guys can be generated). This list is
|
||||
zero terminated. */
|
||||
struct glosym **cmdline_references;
|
||||
int cl_refs_allocated;
|
||||
|
||||
/*
|
||||
* Actual vector of directories to search; this contains those specified with
|
||||
* -L plus the standard ones.
|
||||
*/
|
||||
char **search_dirs;
|
||||
|
||||
/* Length of the vector `search_dirs'. */
|
||||
int n_search_dirs;
|
||||
|
||||
void digest_symbols __P((void));
|
||||
void load_symbols __P((void));
|
||||
void decode_command __P((int, char **));
|
||||
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 write_output __P((void));
|
||||
void write_header __P((void));
|
||||
void write_text __P((void));
|
||||
void write_data __P((void));
|
||||
void write_rel __P((void));
|
||||
void write_syms __P((void));
|
||||
void write_symsegs __P((void));
|
||||
void mywrite ();
|
||||
|
||||
/* In warnings.c: */
|
||||
void perror_name __P((char *));
|
||||
void perror_file __P((struct file_entry *));
|
||||
void fatal_with_file __P((char *, 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((int));
|
||||
void *xrealloc __P((void *, int));
|
||||
void fatal __P((char *, ...));
|
||||
void error __P((char *, ...));
|
||||
void padfile __P((int,int));
|
||||
char *concat __P((char *, char *, char *));
|
||||
int parse __P((char *, char *, 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 *));
|
||||
void add_search_dir __P((char *));
|
||||
void std_search_dirs __P((char *));
|
||||
|
||||
/* In rrs.c: */
|
||||
void init_rrs __P((void));
|
||||
void rrs_add_shobj __P((struct file_entry *));
|
||||
void alloc_rrs_reloc __P((symbol *));
|
||||
void alloc_rrs_segment_reloc __P((struct relocation_info *));
|
||||
void alloc_rrs_jmpslot __P((symbol *));
|
||||
void alloc_rrs_gotslot __P((struct relocation_info *, localsymbol_t *));
|
||||
void alloc_rrs_copy_reloc __P((symbol *));
|
||||
|
||||
/* 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 *));
|
||||
|
||||
#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_link_dynamic __P((struct link_dynamic *));
|
||||
void swap_link_dynamic_2 __P((struct link_dynamic_2 *));
|
||||
void swap_ld_debug __P((struct ld_debug *));
|
||||
void swapin_link_object __P((struct link_object *, int));
|
||||
void swapout_link_object __P((struct link_object *, int));
|
||||
void swapout_fshash __P((struct fshash *, int));
|
||||
#endif
|
13
gnu/usr.bin/ld/ldconfig/Makefile
Normal file
13
gnu/usr.bin/ld/ldconfig/Makefile
Normal file
|
@ -0,0 +1,13 @@
|
|||
# $Id: Makefile,v 1.2 1993/11/03 05:20:49 cgd Exp $
|
||||
|
||||
PROG= ldconfig
|
||||
SRCS= ldconfig.c shlib.c etc.c
|
||||
LDDIR?= $(.CURDIR)/..
|
||||
LDFLAGS += -static
|
||||
CFLAGS += -I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) -O
|
||||
BINDIR= ${DESTDIR}/sbin
|
||||
MAN8 = ldconfig.0
|
||||
|
||||
.PATH: $(LDDIR) $(LDDIR)/$(MACHINE)
|
||||
|
||||
.include <bsd.prog.mk>
|
98
gnu/usr.bin/ld/ldconfig/ldconfig.8
Normal file
98
gnu/usr.bin/ld/ldconfig/ldconfig.8
Normal file
|
@ -0,0 +1,98 @@
|
|||
.Dd October 3, 1993
|
||||
.Dt LDCONFIG 8
|
||||
.Os NetBSD 0.9
|
||||
.Sh NAME
|
||||
.Nm ldconfig
|
||||
.Nd configure the shared library cache
|
||||
.Sh SYNOPSIS
|
||||
.Nm ldconfig
|
||||
.Op Fl rsv
|
||||
.Op Ar directory Ar ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is used to prepare a set of
|
||||
.Dq hints
|
||||
for use by the run-time linker
|
||||
.Xr ld.so
|
||||
to facilitate quick lookup of shared libraries available in multiple
|
||||
directories. It scans a set of built-in system directories and any
|
||||
.Ar directories
|
||||
specified on the command line (in the given order) looking for shared
|
||||
libraries and stores the results in the file
|
||||
.Xr /var/run/ld.so.hints
|
||||
to forstall the overhead that would otherwise result from the
|
||||
directory search operations
|
||||
.Xr ld.so
|
||||
would have to perform to load the required shared libraries.
|
||||
.Pp
|
||||
The shared libraries so found will be automatically available for loading
|
||||
if needed by the program being prepared for execution. This obviates the need
|
||||
for storing search paths within the executable.
|
||||
.Pp
|
||||
The
|
||||
.Ev LD_LIBRARY_PATH
|
||||
environment variable can be used to override the use of
|
||||
directories (or the order thereof) from the cache or to specify additional
|
||||
directories where shared libraries might be found.
|
||||
.Ev LD_LIBRARY_PATH
|
||||
is a
|
||||
.Sq \:
|
||||
separated list of directory paths which are searched by
|
||||
.Xr ld.so
|
||||
when it needs to load a shared library. It can be viewed as the run-time
|
||||
equivalent of the
|
||||
.Fl L
|
||||
switch of
|
||||
.Xr ld.
|
||||
.Pp
|
||||
.Nm Ldconfig
|
||||
is typically run as part of the boot sequence.
|
||||
.Pp
|
||||
The following options recognized by
|
||||
.Nm ldconfig:
|
||||
.Bl -tag -width indent
|
||||
.It Fl r
|
||||
Lists the current contents of
|
||||
.Xr ld.so.hints
|
||||
on the standard output. The hints file will not be modified.
|
||||
.It Fl s
|
||||
Do not scan
|
||||
.Nm ldconfig
|
||||
's builtin system directories
|
||||
.Sq /usr/lib
|
||||
and
|
||||
.Sq /usr/local/lib
|
||||
for shared libraries.
|
||||
.It Fl v
|
||||
Switch on verbose mode.
|
||||
.Sh Security
|
||||
Special care must be taken when loading shared libraries into the address
|
||||
space of
|
||||
.Ev set-user-Id
|
||||
programs. Whenever such a program is run,
|
||||
.Xr ld.so
|
||||
will only load shared libraries from the
|
||||
.Ev ld.so.hints
|
||||
file. In particular, the
|
||||
.Ev LD_LIBRARY_PATH
|
||||
is not used to search for libraries. Thus, the role of ldconfig is dual. In
|
||||
addition to building a set of hints for quick lookup, it also serves to
|
||||
specify the trusted collection of directories from which shared objects can
|
||||
be safely loaded. It is presumed that the set of directories specified to
|
||||
.Nm ldconfig
|
||||
are under control of the system's administrator.
|
||||
.Xr ld.so
|
||||
further assists set-user-Id programs by erasing the
|
||||
.Ev LD_LIBRARY_PATH
|
||||
from the environment.
|
||||
|
||||
.Sh FILES
|
||||
.Xr /var/run/ld.so.hints
|
||||
.Sh SEE ALSO
|
||||
.Xr ld 1 ,
|
||||
.Xr link 5
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility first appeared in SunOS 4.0, it appeared in its current form
|
||||
in NetBSD 0.9a.
|
411
gnu/usr.bin/ld/ldconfig/ldconfig.c
Normal file
411
gnu/usr.bin/ld/ldconfig/ldconfig.c
Normal file
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* 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 withough 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: ldconfig.c,v 1.1 1993/10/23 00:17:03 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ar.h>
|
||||
#include <ranlib.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
#undef major
|
||||
#undef minor
|
||||
|
||||
char *progname;
|
||||
static int verbose;
|
||||
static int nostd;
|
||||
static int justread;
|
||||
|
||||
#define MAXDEWEY 8
|
||||
struct shlib_list {
|
||||
/* Internal list of shared libraries found */
|
||||
char *name;
|
||||
char *path;
|
||||
int dewey[MAXDEWEY];
|
||||
int ndewey;
|
||||
#define major dewey[0]
|
||||
#define minor dewey[1]
|
||||
struct shlib_list *next;
|
||||
};
|
||||
|
||||
static struct shlib_list *shlib_head = NULL, **shlib_tail = &shlib_head;
|
||||
|
||||
static void enter __P((char *, char *, char *, int *, int));
|
||||
static int dodir __P((char *));
|
||||
static int build_hints __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i, c;
|
||||
int rval = 0;
|
||||
extern int optind;
|
||||
|
||||
if ((progname = strrchr(argv[0], '/')) == NULL)
|
||||
progname = argv[0];
|
||||
else
|
||||
progname++;
|
||||
|
||||
while ((c = getopt(argc, argv, "rsv")) != EOF) {
|
||||
switch (c) {
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 's':
|
||||
nostd = 1;
|
||||
break;
|
||||
case 'r':
|
||||
justread = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Usage: %s [-v] [dir ...]\n", progname);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (justread)
|
||||
return listhints();
|
||||
|
||||
if (!nostd)
|
||||
std_search_dirs(NULL);
|
||||
|
||||
for (i = 0; i < n_search_dirs; i++)
|
||||
rval |= dodir(search_dirs[i]);
|
||||
|
||||
for (i = optind; i < argc; i++)
|
||||
rval |= dodir(argv[i]);
|
||||
|
||||
rval |= build_hints();
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
dodir(dir)
|
||||
char *dir;
|
||||
{
|
||||
DIR *dd;
|
||||
struct dirent *dp;
|
||||
char name[MAXPATHLEN], rest[MAXPATHLEN];
|
||||
int dewey[MAXDEWEY], ndewey;
|
||||
|
||||
if ((dd = opendir(dir)) == NULL) {
|
||||
perror(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dd)) != NULL) {
|
||||
int n;
|
||||
|
||||
name[0] = rest[0] = '\0';
|
||||
|
||||
n = sscanf(dp->d_name, "lib%[^.].so.%s",
|
||||
name, rest);
|
||||
|
||||
if (n < 2 || rest[0] == '\0')
|
||||
continue;
|
||||
|
||||
ndewey = getdewey(dewey, rest);
|
||||
enter(dir, dp->d_name, name, dewey, ndewey);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
enter(dir, file, name, dewey, ndewey)
|
||||
char *dir, *file, *name;
|
||||
int dewey[], ndewey;
|
||||
{
|
||||
struct shlib_list *shp;
|
||||
|
||||
for (shp = shlib_head; shp; shp = shp->next) {
|
||||
if (strcmp(name, shp->name) != 0 || major != shp->major)
|
||||
continue;
|
||||
|
||||
/* Name matches existing entry */
|
||||
if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) {
|
||||
|
||||
/* Update this entry with higher versioned lib */
|
||||
if (verbose)
|
||||
printf("Updating lib%s.%d.%d to %s/%s\n",
|
||||
shp->name, shp->major, shp->minor,
|
||||
dir, file);
|
||||
|
||||
free(shp->name);
|
||||
shp->name = strdup(name);
|
||||
free(shp->path);
|
||||
shp->path = concat(dir, "/", file);
|
||||
bcopy(dewey, shp->dewey, sizeof(shp->dewey));
|
||||
shp->ndewey = ndewey;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (shp)
|
||||
/* Name exists: older version or just updated */
|
||||
return;
|
||||
|
||||
/* Allocate new list element */
|
||||
if (verbose)
|
||||
printf("Adding %s/%s\n", dir, file);
|
||||
|
||||
shp = (struct shlib_list *)xmalloc(sizeof *shp);
|
||||
shp->name = strdup(name);
|
||||
shp->path = concat(dir, "/", file);
|
||||
bcopy(dewey, shp->dewey, MAXDEWEY);
|
||||
shp->ndewey = ndewey;
|
||||
shp->next = NULL;
|
||||
|
||||
*shlib_tail = shp;
|
||||
shlib_tail = &shp->next;
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG
|
||||
/* test */
|
||||
#undef _PATH_LD_HINTS
|
||||
#define _PATH_LD_HINTS "./ld.so.hints"
|
||||
#endif
|
||||
|
||||
int
|
||||
hinthash(cp, vmajor, vminor)
|
||||
char *cp;
|
||||
int vmajor, vminor;
|
||||
{
|
||||
int k = 0;
|
||||
|
||||
while (*cp)
|
||||
k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
|
||||
|
||||
k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
|
||||
k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
int
|
||||
build_hints()
|
||||
{
|
||||
struct hints_header hdr;
|
||||
struct hints_bucket *blist;
|
||||
struct shlib_list *shp;
|
||||
char *strtab;
|
||||
int i, n, str_index = 0;
|
||||
int strtab_sz = 0; /* Total length of strings */
|
||||
int nhints = 0; /* Total number of hints */
|
||||
int fd;
|
||||
char *tmpfile;
|
||||
|
||||
for (shp = shlib_head; shp; shp = shp->next) {
|
||||
strtab_sz += 1 + strlen(shp->name);
|
||||
strtab_sz += 1 + strlen(shp->path);
|
||||
nhints++;
|
||||
}
|
||||
|
||||
/* Fill hints file header */
|
||||
hdr.hh_magic = HH_MAGIC;
|
||||
hdr.hh_version = LD_HINTS_VERSION_1;
|
||||
hdr.hh_nbucket = 1 * nhints;
|
||||
n = hdr.hh_nbucket * sizeof(struct hints_bucket);
|
||||
hdr.hh_hashtab = sizeof(struct hints_header);
|
||||
hdr.hh_strtab = hdr.hh_hashtab + n;
|
||||
hdr.hh_strtab_sz = strtab_sz;
|
||||
hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz;
|
||||
|
||||
if (verbose)
|
||||
printf("Totals: entries %d, buckets %d, string size %d\n",
|
||||
nhints, hdr.hh_nbucket, strtab_sz);
|
||||
|
||||
/* Allocate buckets and string table */
|
||||
blist = (struct hints_bucket *)xmalloc(n);
|
||||
bzero((char *)blist, n);
|
||||
for (i = 0; i < hdr.hh_nbucket; i++)
|
||||
/* Empty all buckets */
|
||||
blist[i].hi_next = -1;
|
||||
|
||||
strtab = (char *)xmalloc(strtab_sz);
|
||||
|
||||
/* Enter all */
|
||||
for (shp = shlib_head; shp; shp = shp->next) {
|
||||
struct hints_bucket *bp;
|
||||
|
||||
bp = blist +
|
||||
(hinthash(shp->name, shp->major, shp->minor) % hdr.hh_nbucket);
|
||||
|
||||
if (bp->hi_pathx) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < hdr.hh_nbucket; i++) {
|
||||
if (blist[i].hi_pathx == 0)
|
||||
break;
|
||||
}
|
||||
if (i == hdr.hh_nbucket) {
|
||||
fprintf(stderr, "Bummer!\n");
|
||||
return -1;
|
||||
}
|
||||
while (bp->hi_next != -1)
|
||||
bp = &blist[bp->hi_next];
|
||||
bp->hi_next = i;
|
||||
bp = blist + i;
|
||||
}
|
||||
|
||||
/* Insert strings in string table */
|
||||
bp->hi_namex = str_index;
|
||||
strcpy(strtab + str_index, shp->name);
|
||||
str_index += 1 + strlen(shp->name);
|
||||
|
||||
bp->hi_pathx = str_index;
|
||||
strcpy(strtab + str_index, shp->path);
|
||||
str_index += 1 + strlen(shp->path);
|
||||
|
||||
/* Copy versions */
|
||||
bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey));
|
||||
bp->hi_ndewey = shp->ndewey;
|
||||
}
|
||||
|
||||
tmpfile = concat(_PATH_LD_HINTS, "+", "");
|
||||
if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, 0444)) == -1) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mywrite(&hdr, 1, sizeof(struct hints_header), fd);
|
||||
mywrite(blist, hdr.hh_nbucket, sizeof(struct hints_bucket), fd);
|
||||
mywrite(strtab, strtab_sz, 1, fd);
|
||||
|
||||
if (close(fd) != 0) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now, install real file */
|
||||
if (unlink(_PATH_LD_HINTS) != 0 && errno != ENOENT) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rename(tmpfile, _PATH_LD_HINTS) != 0) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
listhints()
|
||||
{
|
||||
int fd;
|
||||
caddr_t addr;
|
||||
long msize;
|
||||
struct hints_header *hdr;
|
||||
struct hints_bucket *blist;
|
||||
char *strtab;
|
||||
int i;
|
||||
|
||||
if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msize = PAGSIZ;
|
||||
addr = mmap(0, msize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
|
||||
|
||||
if (addr == (caddr_t)-1) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr = (struct hints_header *)addr;
|
||||
if (HH_BADMAG(*hdr)) {
|
||||
fprintf(stderr, "%s: Bad magic: %d\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->hh_version != LD_HINTS_VERSION_1) {
|
||||
fprintf(stderr, "Unsupported version: %d\n", hdr->hh_version);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->hh_ehints > msize) {
|
||||
if (mmap(addr+msize, hdr->hh_ehints - msize,
|
||||
PROT_READ, MAP_FILE|MAP_COPY|MAP_FIXED,
|
||||
fd, msize) != (caddr_t)(addr+msize)) {
|
||||
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
blist = (struct hints_bucket *)(addr + hdr->hh_hashtab);
|
||||
strtab = (char *)(addr + hdr->hh_strtab);
|
||||
|
||||
printf("%s:\n", _PATH_LD_HINTS);
|
||||
for (i = 0; i < hdr->hh_nbucket; i++) {
|
||||
struct hints_bucket *bp = &blist[i];
|
||||
|
||||
/* Sanity check */
|
||||
if (bp->hi_namex >= hdr->hh_strtab_sz) {
|
||||
fprintf(stderr, "Bad name index: %#x\n", bp->hi_namex);
|
||||
return -1;
|
||||
}
|
||||
if (bp->hi_pathx >= hdr->hh_strtab_sz) {
|
||||
fprintf(stderr, "Bad path index: %#x\n", bp->hi_pathx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("\t-l%s.%d.%d => %s\n",
|
||||
strtab + bp->hi_namex, bp->hi_major, bp->hi_minor,
|
||||
strtab + bp->hi_pathx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
7
gnu/usr.bin/ld/ldd/Makefile
Normal file
7
gnu/usr.bin/ld/ldd/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
# $Id: Makefile,v 1.2 1993/10/22 21:10:42 pk Exp $
|
||||
|
||||
PROG= ldd
|
||||
SRCS= ldd.c
|
||||
BINDIR= ${DESTDIR}/usr/bin
|
||||
|
||||
.include <bsd.prog.mk>
|
25
gnu/usr.bin/ld/ldd/ldd.1
Normal file
25
gnu/usr.bin/ld/ldd/ldd.1
Normal file
|
@ -0,0 +1,25 @@
|
|||
.Dd October 22, 1993
|
||||
.Dt LDD 1
|
||||
.Os NetBSD 0.9
|
||||
.Sh NAME
|
||||
.Nm ldd
|
||||
.Nd list dynamic object dependencies
|
||||
.Sh SYNOPSIS
|
||||
.Nm ldd
|
||||
.Op Ar filename Ar ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm ldd
|
||||
displays all shared objects that are needed to run the given program.
|
||||
Contrary to nm(1), the list includes
|
||||
.Dq indirect
|
||||
depedencies that are the result of needed shared objects which themselves
|
||||
depend on yet other shared objects.
|
||||
.Sh SEE ALSO
|
||||
.Xr ld 1 ,
|
||||
.Xr ld.so 1 ,
|
||||
.Xr nm 1
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm ldd
|
||||
utility first appeared in SunOS 4.0, it appeared in its current form
|
||||
in NetBSD 0.9a.
|
139
gnu/usr.bin/ld/ldd/ldd.c
Normal file
139
gnu/usr.bin/ld/ldd/ldd.c
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* 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 withough 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: ldd.c,v 1.3 1993/10/31 14:54:29 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <a.out.h>
|
||||
|
||||
static char *progname;
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s <filename> ...\n", progname);
|
||||
}
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int rval = 0;
|
||||
int c;
|
||||
extern int optind;
|
||||
|
||||
if ((progname = strrchr(argv[0], '/')) == NULL)
|
||||
progname = argv[0];
|
||||
else
|
||||
progname++;
|
||||
|
||||
while ((c = getopt(argc, argv, "")) != EOF) {
|
||||
switch (c) {
|
||||
default:
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc <= 0) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* ld.so magic */
|
||||
setenv("LD_TRACE_LOADED_OBJECTS", "", 1);
|
||||
|
||||
while (argc--) {
|
||||
int fd;
|
||||
struct exec hdr;
|
||||
int status;
|
||||
|
||||
if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
|
||||
perror(*argv);
|
||||
rval |= 1;
|
||||
argv++;
|
||||
continue;
|
||||
}
|
||||
if (read(fd, &hdr, sizeof hdr) != sizeof hdr ||
|
||||
!(N_GETFLAG(hdr) & EX_DYNAMIC)) {
|
||||
fprintf(stderr, "%s: not a dynamic executable\n",
|
||||
*argv);
|
||||
(void)close(fd);
|
||||
rval |= 1;
|
||||
argv++;
|
||||
continue;
|
||||
}
|
||||
(void)close(fd);
|
||||
|
||||
printf("%s:\n", *argv);
|
||||
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
perror("fork");
|
||||
exit(1);
|
||||
break;
|
||||
default:
|
||||
if (wait(&status) <= 0)
|
||||
perror("wait");
|
||||
|
||||
if (WIFSIGNALED(status)) {
|
||||
fprintf(stderr, "%s: signal %d\n",
|
||||
*argv, WTERMSIG(status));
|
||||
rval |= 1;
|
||||
} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
|
||||
fprintf(stderr, "%s: exit status %d\n",
|
||||
*argv, WEXITSTATUS(status));
|
||||
rval |= 1;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
rval != execl(*argv, *argv, NULL) != 0;
|
||||
perror(*argv);
|
||||
_exit(1);
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
640
gnu/usr.bin/ld/lib.c
Normal file
640
gnu/usr.bin/ld/lib.c
Normal file
|
@ -0,0 +1,640 @@
|
|||
/*
|
||||
* $Id: lib.c,v 1.3 1993/11/01 16:26:17 pk Exp $ - library routines
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <ar.h>
|
||||
#include <ranlib.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
char **search_dirs;
|
||||
|
||||
/* Length of the vector `search_dirs'. */
|
||||
int n_search_dirs;
|
||||
|
||||
struct file_entry *decode_library_subfile();
|
||||
void linear_library(), symdef_library();
|
||||
|
||||
/*
|
||||
* Search the library ENTRY, already open on descriptor DESC. 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(desc, entry)
|
||||
int desc;
|
||||
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(desc, 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(desc, entry, member_length);
|
||||
else
|
||||
linear_library(desc, 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 DESC.
|
||||
* SUBFILE_OFFSET is the byte index in the library of this member's header.
|
||||
* We store the length of the member into *LENGTH_LOC.
|
||||
*/
|
||||
|
||||
struct file_entry *
|
||||
decode_library_subfile(desc, library_entry, subfile_offset, length_loc)
|
||||
int desc;
|
||||
struct file_entry *library_entry;
|
||||
int subfile_offset;
|
||||
int *length_loc;
|
||||
{
|
||||
int bytes_read;
|
||||
register int namelen;
|
||||
int member_length;
|
||||
register char *name;
|
||||
struct ar_hdr hdr1;
|
||||
register struct file_entry *subentry;
|
||||
|
||||
lseek(desc, subfile_offset, 0);
|
||||
|
||||
bytes_read = read(desc, &hdr1, sizeof hdr1);
|
||||
if (!bytes_read)
|
||||
return 0; /* end of archive */
|
||||
|
||||
if (sizeof hdr1 != bytes_read)
|
||||
fatal_with_file("malformed library archive ", library_entry);
|
||||
|
||||
if (sscanf(hdr1.ar_size, "%d", &member_length) != 1)
|
||||
fatal_with_file("malformatted header of archive member in ", library_entry);
|
||||
|
||||
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++);
|
||||
|
||||
name = (char *) xmalloc(namelen + 1);
|
||||
strncpy(name, hdr1.ar_name, namelen);
|
||||
name[namelen] = 0;
|
||||
|
||||
subentry->filename = name;
|
||||
subentry->local_sym_name = name;
|
||||
subentry->symbols = 0;
|
||||
subentry->strings = 0;
|
||||
subentry->subfiles = 0;
|
||||
subentry->starting_offset = subfile_offset + sizeof hdr1;
|
||||
subentry->superfile = library_entry;
|
||||
subentry->library_flag = 0;
|
||||
subentry->header_read_flag = 0;
|
||||
subentry->just_syms_flag = 0;
|
||||
subentry->chain = 0;
|
||||
subentry->total_size = member_length;
|
||||
|
||||
(*length_loc) = member_length;
|
||||
|
||||
return subentry;
|
||||
}
|
||||
|
||||
int subfile_wanted_p();
|
||||
|
||||
/*
|
||||
* Search a library that has a __.SYMDEF member. DESC 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.
|
||||
*/
|
||||
|
||||
void
|
||||
symdef_library(desc, entry, member_length)
|
||||
int desc;
|
||||
struct file_entry *entry;
|
||||
int member_length;
|
||||
{
|
||||
int *symdef_data = (int *) xmalloc(member_length);
|
||||
register struct ranlib *symdef_base;
|
||||
char *sym_name_base;
|
||||
int number_of_symdefs;
|
||||
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(desc, symdef_data, member_length);
|
||||
if (bytes_read != member_length)
|
||||
fatal_with_file("malformatted __.SYMDEF in ", entry);
|
||||
|
||||
number_of_symdefs = md_swap_long(*symdef_data) / sizeof(struct ranlib);
|
||||
if (number_of_symdefs < 0 ||
|
||||
number_of_symdefs * sizeof(struct ranlib) + 2 * sizeof(int) > member_length)
|
||||
fatal_with_file("malformatted __.SYMDEF in ", entry);
|
||||
|
||||
symdef_base = (struct ranlib *) (symdef_data + 1);
|
||||
length_of_strings = md_swap_long(*(int *) (symdef_base + number_of_symdefs));
|
||||
|
||||
if (length_of_strings < 0
|
||||
|| number_of_symdefs * sizeof(struct ranlib) + length_of_strings
|
||||
+ 2 * sizeof(int) > member_length)
|
||||
fatal_with_file("malformatted __.SYMDEF in ", entry);
|
||||
|
||||
sym_name_base = sizeof(int) + (char *) (symdef_base + number_of_symdefs);
|
||||
|
||||
/* Check all the string indexes for validity. */
|
||||
md_swapin_ranlib_hdr(symdef_base, number_of_symdefs);
|
||||
for (i = 0; i < number_of_symdefs; i++) {
|
||||
register int index = symdef_base[i].ran_un.ran_strx;
|
||||
if (index < 0 || index >= length_of_strings
|
||||
|| (index && *(sym_name_base + index - 1)))
|
||||
fatal_with_file("malformatted __.SYMDEF in ", 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 < number_of_symdefs &&
|
||||
((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 (!(link_mode & FORCEARCHIVE) &&
|
||||
(!sp || !sp->referenced || sp->defined))
|
||||
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(desc,
|
||||
entry, offset, &junk);
|
||||
if (subentry == 0)
|
||||
fatal(
|
||||
"invalid offset for %s in symbol table of %s",
|
||||
sym_name_base
|
||||
+ symdef_base[i].ran_un.ran_strx,
|
||||
entry->filename);
|
||||
read_entry_symbols(desc, subentry);
|
||||
subentry->strings = (char *)
|
||||
malloc(subentry->string_size);
|
||||
read_entry_strings(desc, subentry);
|
||||
|
||||
/*
|
||||
* Now scan the symbol table and decide whether to
|
||||
* load.
|
||||
*/
|
||||
|
||||
if (!(link_mode & FORCEARCHIVE) &&
|
||||
!subfile_wanted_p(subentry)) {
|
||||
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(desc, 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 < number_of_symdefs; 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
|
||||
* again.
|
||||
*/
|
||||
free(subentry->strings);
|
||||
subentry->strings = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free(symdef_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search a library that has no __.SYMDEF. ENTRY is the library's file_entry.
|
||||
* DESC is the descriptor it is open on.
|
||||
*/
|
||||
|
||||
void
|
||||
linear_library(desc, entry)
|
||||
int desc;
|
||||
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(desc, entry, this_subfile_offset,
|
||||
&member_length);
|
||||
|
||||
if (!subentry)
|
||||
return;
|
||||
|
||||
read_entry_symbols(desc, subentry);
|
||||
subentry->strings = (char *) alloca(subentry->string_size);
|
||||
read_entry_strings(desc, subentry);
|
||||
|
||||
if (!(link_mode & FORCEARCHIVE) &&
|
||||
!subfile_wanted_p(subentry)) {
|
||||
free(subentry->symbols);
|
||||
free(subentry);
|
||||
} else {
|
||||
read_entry_relocation(desc, 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.
|
||||
*/
|
||||
|
||||
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->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->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->max_common_size)
|
||||
common_defined_global_count++;
|
||||
|
||||
if (sp->max_common_size < p->n_value)
|
||||
sp->max_common_size = p->n_value;
|
||||
if (!sp->defined)
|
||||
undefined_global_sym_count--;
|
||||
sp->defined = type;
|
||||
continue;
|
||||
}
|
||||
if (write_map) {
|
||||
print_file_name(entry, stdout);
|
||||
fprintf(stdout, " needed due to %s\n", sp->name);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
struct localsymbol *lsp;
|
||||
int defs = 0;
|
||||
|
||||
/* Check for undefined symbols in shared objects */
|
||||
for (lsp = sp->sorefs; lsp; lsp = lsp->next) {
|
||||
type = lsp->nzlist.nlist.n_type;
|
||||
if ( (type & N_EXT) &&
|
||||
(type & N_STAB) == 0 &&
|
||||
type != (N_UNDF | N_EXT))
|
||||
goto xxx;
|
||||
}
|
||||
if (write_map) {
|
||||
print_file_name(entry, stdout);
|
||||
fprintf(stdout, " needed due to shared lib ref %s\n", sp->name);
|
||||
}
|
||||
return 1;
|
||||
xxx: ;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the symbols of dynamic entity ENTRY into core. Assume it is already
|
||||
* open, on descriptor DESC.
|
||||
*/
|
||||
void
|
||||
read_shared_object (desc, entry)
|
||||
struct file_entry *entry;
|
||||
int desc;
|
||||
{
|
||||
struct link_dynamic dyn;
|
||||
struct link_dynamic_2 dyn2;
|
||||
struct nlist *np;
|
||||
struct nzlist *nzp;
|
||||
int n, i, has_nz = 0;
|
||||
|
||||
if (!entry->header_read_flag)
|
||||
read_header (desc, entry);
|
||||
|
||||
/* Read DYNAMIC structure (first in data segment) */
|
||||
lseek (desc,
|
||||
text_offset (entry) + entry->header.a_text,
|
||||
L_SET);
|
||||
if (read(desc, &dyn, sizeof dyn) != sizeof dyn) {
|
||||
fatal_with_file (
|
||||
"premature eof in data segment of ", entry);
|
||||
}
|
||||
md_swapin_link_dynamic(&dyn);
|
||||
|
||||
/* Check version */
|
||||
switch (dyn.ld_version) {
|
||||
default:
|
||||
fatal_with_file( "unsupported _DYNAMIC version ", entry);
|
||||
break;
|
||||
case LD_VERSION_SUN:
|
||||
break;
|
||||
case LD_VERSION_BSD:
|
||||
has_nz = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read link_dynamic_2 struct (from data segment) */
|
||||
lseek (desc,
|
||||
text_offset(entry) + dyn.ld_un.ld_2,
|
||||
L_SET);
|
||||
if (read(desc, &dyn2, sizeof dyn2) != sizeof dyn2) {
|
||||
fatal_with_file( "premature eof in data segment of ", entry);
|
||||
}
|
||||
md_swapin_link_dynamic_2(&dyn2);
|
||||
|
||||
/* Read symbols (text segment) */
|
||||
n = dyn2.ld_strings - dyn2.ld_symbols;
|
||||
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));
|
||||
lseek(desc, text_offset (entry) + dyn2.ld_symbols, L_SET);
|
||||
if (read(desc, (char *)nzp, n) != n) {
|
||||
fatal_with_file(
|
||||
"premature eof while reading dyn syms ", 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].gotslot_offset = -1;
|
||||
}
|
||||
|
||||
/* Read strings (text segment) */
|
||||
n = entry->string_size = dyn2.ld_str_sz;
|
||||
entry->strings = (char *) alloca(n);
|
||||
entry->strings_offset = text_offset (entry) + dyn2.ld_strings;
|
||||
lseek(desc, entry->strings_offset, L_SET);
|
||||
if (read(desc, entry->strings, n) != n) {
|
||||
fatal_with_file(
|
||||
"premature eof while reading dyn strings ", entry);
|
||||
}
|
||||
enter_file_symbols (entry);
|
||||
entry->strings = 0;
|
||||
|
||||
/* TODO: examine needed shared objects */
|
||||
if (dyn2.ld_need) {
|
||||
}
|
||||
}
|
||||
|
||||
#undef major
|
||||
#undef minor
|
||||
|
||||
int
|
||||
findlib(p)
|
||||
struct file_entry *p;
|
||||
{
|
||||
int desc;
|
||||
int i;
|
||||
int len;
|
||||
int major = -1, minor = -1;
|
||||
char *cp, *fname = NULL;
|
||||
|
||||
if (p->search_dynamic_flag == 0)
|
||||
goto dot_a;
|
||||
|
||||
fname = findshlib(p->filename, &major, &minor);
|
||||
|
||||
if (fname && (desc = open (fname, O_RDONLY, 0)) > 0) {
|
||||
p->filename = fname;
|
||||
p->lib_major = major;
|
||||
p->lib_minor = minor;
|
||||
p->search_dirs_flag = 0;
|
||||
return desc;
|
||||
}
|
||||
free (fname);
|
||||
|
||||
dot_a:
|
||||
p->search_dynamic_flag = 0;
|
||||
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 *string
|
||||
= concat (search_dirs[i], "/", fname);
|
||||
desc = open (string, O_RDONLY, 0);
|
||||
if (desc > 0) {
|
||||
p->filename = string;
|
||||
p->search_dirs_flag = 0;
|
||||
break;
|
||||
}
|
||||
free (string);
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
1064
gnu/usr.bin/ld/rrs.c
Normal file
1064
gnu/usr.bin/ld/rrs.c
Normal file
File diff suppressed because it is too large
Load diff
24
gnu/usr.bin/ld/rtld/Makefile
Normal file
24
gnu/usr.bin/ld/rtld/Makefile
Normal file
|
@ -0,0 +1,24 @@
|
|||
# $Id: Makefile,v 1.2 1993/10/27 00:55:24 pk Exp $
|
||||
|
||||
PROG= ld.so
|
||||
SRCS= mdprologue.S rtld.c shlib.c etc.c md.c
|
||||
NOMAN= noman
|
||||
LDDIR?= $(.CURDIR)/..
|
||||
#PICFLAG=-pic
|
||||
PICFLAG=-fpic
|
||||
CFLAGS += -I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) -O $(PICFLAG) -DRTLD
|
||||
LDFLAGS = -Bshareable -Bsymbolic -assert nosymbolic
|
||||
LIBS = -lc_pic
|
||||
BINDIR= /usr/libexec
|
||||
|
||||
.PATH: $(LDDIR) $(LDDIR)/$(MACHINE)
|
||||
|
||||
.SUFFIXES: .S
|
||||
|
||||
$(PROG):
|
||||
$(LD) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIBS)
|
||||
|
||||
.S.o:
|
||||
$(CPP) $(.IMPSRC) | $(AS) -k -o $(.TARGET) -
|
||||
|
||||
.include <bsd.prog.mk>
|
39
gnu/usr.bin/ld/rtld/md-prologue.c
Normal file
39
gnu/usr.bin/ld/rtld/md-prologue.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* rtld entry pseudo code - turn into assembler and tweak it
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/types.h>
|
||||
#include <a.out.h>
|
||||
#include "link.h"
|
||||
#include "md.h"
|
||||
|
||||
extern long _GOT_[];
|
||||
extern void (*rtld)();
|
||||
extern void (*binder())();
|
||||
|
||||
void
|
||||
rtld_entry(version, crtp)
|
||||
int version;
|
||||
struct crt *crtp;
|
||||
{
|
||||
register struct link_dynamic *dp;
|
||||
register void (*f)();
|
||||
|
||||
/* __DYNAMIC is first entry in GOT */
|
||||
dp = (struct link_dynamic *) (_GOT_[0]+crtp->crt_ba);
|
||||
|
||||
f = (void (*)())((long)rtld + crtp->crt_ba);
|
||||
(*f)(version, crtp, dp);
|
||||
}
|
||||
|
||||
void
|
||||
binder_entry()
|
||||
{
|
||||
extern int PC;
|
||||
struct jmpslot *sp;
|
||||
void (*func)();
|
||||
|
||||
func = binder(PC, sp->reloc_index & 0x003fffff);
|
||||
(*func)();
|
||||
}
|
1026
gnu/usr.bin/ld/rtld/rtld.c
Normal file
1026
gnu/usr.bin/ld/rtld/rtld.c
Normal file
File diff suppressed because it is too large
Load diff
203
gnu/usr.bin/ld/shlib.c
Normal file
203
gnu/usr.bin/ld/shlib.c
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* $Id: shlib.c,v 1.3 1993/10/23 00:34:26 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <a.out.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
/*
|
||||
* Standard directories to search for files specified by -l.
|
||||
*/
|
||||
#ifndef STANDARD_SEARCH_DIRS
|
||||
#define STANDARD_SEARCH_DIRS "/usr/lib", "/usr/local/lib"
|
||||
#endif
|
||||
|
||||
char *standard_search_dirs[] = {
|
||||
STANDARD_SEARCH_DIRS
|
||||
};
|
||||
|
||||
int n_search_dirs;
|
||||
|
||||
void
|
||||
add_search_dir(name)
|
||||
char *name;
|
||||
{
|
||||
n_search_dirs++;
|
||||
search_dirs = (char **)xrealloc(search_dirs,
|
||||
n_search_dirs * sizeof(char *));
|
||||
search_dirs[n_search_dirs - 1] = strdup(name);
|
||||
}
|
||||
|
||||
void
|
||||
std_search_dirs(paths)
|
||||
char *paths;
|
||||
{
|
||||
char *cp;
|
||||
int i, n;
|
||||
|
||||
if (paths != NULL)
|
||||
/* Add search directories from `paths' */
|
||||
while ((cp = strtok(paths, ":")) != NULL) {
|
||||
paths = NULL;
|
||||
add_search_dir(cp);
|
||||
}
|
||||
|
||||
/* 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++;
|
||||
if (!isdigit(*cp))
|
||||
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;
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
char *name;
|
||||
int *majorp, *minorp;
|
||||
{
|
||||
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;
|
||||
|
||||
if (dd == NULL)
|
||||
continue;
|
||||
|
||||
while ((dp = readdir(dd)) != NULL) {
|
||||
int n, j, might_take_it = 0;
|
||||
|
||||
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 && 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);
|
||||
bcopy(tmp, dewey, sizeof(dewey));
|
||||
ndewey = n;
|
||||
*majorp = dewey[0];
|
||||
*minorp = dewey[1];
|
||||
}
|
||||
closedir(dd);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
35
gnu/usr.bin/ld/sparc/md-static-funcs.c
Normal file
35
gnu/usr.bin/ld/sparc/md-static-funcs.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
/*
|
||||
* Simple SPARC relocations for the benefit of self-relocation of ld.so
|
||||
* avoiding the use of global variables (ie. reloc_bitshift[] et. al.).
|
||||
* Only types supported are RELOC_32 and RELOC_RELATIVE.
|
||||
*
|
||||
* This *must* be a static function, so it is not called through a jmpslot.
|
||||
*/
|
||||
static void
|
||||
md_relocate_simple(r, relocation, addr)
|
||||
struct relocation_info *r;
|
||||
long relocation;
|
||||
char *addr;
|
||||
{
|
||||
register unsigned long mask;
|
||||
register unsigned long shift;
|
||||
|
||||
switch (r->r_type) {
|
||||
case RELOC_32:
|
||||
mask = 0xffffffff;
|
||||
shift = 0;
|
||||
break;
|
||||
case RELOC_RELATIVE:
|
||||
mask = 0x003fffff;
|
||||
shift = 10;
|
||||
break;
|
||||
}
|
||||
relocation += (*(long *)addr & mask) << shift;
|
||||
relocation >>= shift;
|
||||
relocation &= mask;
|
||||
|
||||
*(long *) (addr) &= ~mask;
|
||||
*(long *) (addr) |= relocation;
|
||||
}
|
||||
|
279
gnu/usr.bin/ld/sparc/md.c
Normal file
279
gnu/usr.bin/ld/sparc/md.c
Normal file
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* $Id: md.c,v 1.2 1993/10/27 00:56:17 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
/*
|
||||
* Relocation masks and sizes for the Sparc architecture.
|
||||
*
|
||||
* Note that these are very dependent on the order of the enums in
|
||||
* enum reloc_type (in a.out.h); if they change the following must be
|
||||
* changed.
|
||||
* Also, note that RELOC_RELATIVE is handled as if it were a RELOC_HI22.
|
||||
* This should work provided that relocations values have zeroes in their
|
||||
* least significant 10 bits. As RELOC_RELATIVE is used only to relocate
|
||||
* with load address values - which are page aligned - this condition is
|
||||
* fulfilled as long as the system's page size is > 1024 (and a power of 2).
|
||||
*/
|
||||
static int reloc_target_rightshift[] = {
|
||||
0, 0, 0, /* RELOC_8, _16, _32 */
|
||||
0, 0, 0, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
|
||||
10, 0, /* HI22, _22 */
|
||||
0, 0, /* RELOC_13, _LO10 */
|
||||
0, 0, /* _SFA_BASE, _SFA_OFF13 */
|
||||
0, 0, 10, /* _BASE10, _BASE13, _BASE22 */
|
||||
0, 10, /* _PC10, _PC22 */
|
||||
2, 0, /* _JMP_TBL, _SEGOFF16 */
|
||||
0, 0, 0 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
|
||||
};
|
||||
static int reloc_target_size[] = {
|
||||
0, 1, 2, /* RELOC_8, _16, _32 */
|
||||
0, 1, 2, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
|
||||
2, 2, /* HI22, _22 */
|
||||
2, 2, /* RELOC_13, _LO10 */
|
||||
2, 2, /* _SFA_BASE, _SFA_OFF13 */
|
||||
2, 2, 2, /* _BASE10, _BASE13, _BASE22 */
|
||||
2, 2, /* _PC10, _PC22 */
|
||||
2, 0, /* _JMP_TBL, _SEGOFF16 */
|
||||
2, 0, 2 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
|
||||
};
|
||||
static int reloc_target_bitsize[] = {
|
||||
8, 16, 32, /* RELOC_8, _16, _32 */
|
||||
8, 16, 32, 30, 22, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
|
||||
22, 22, /* HI22, _22 */
|
||||
13, 10, /* RELOC_13, _LO10 */
|
||||
32, 32, /* _SFA_BASE, _SFA_OFF13 */
|
||||
10, 13, 22, /* _BASE10, _BASE13, _BASE22 */
|
||||
10, 22, /* _PC10, _PC22 */
|
||||
30, 0, /* _JMP_TBL, _SEGOFF16 */
|
||||
32, 0, 22 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Get relocation addend corresponding to relocation record RP
|
||||
* ADDR unused by SPARC impl.
|
||||
*/
|
||||
long
|
||||
md_get_addend(r, addr)
|
||||
struct relocation_info *r;
|
||||
unsigned char *addr;
|
||||
{
|
||||
return r->r_addend;
|
||||
}
|
||||
|
||||
void
|
||||
md_relocate(r, relocation, addr, relocatable_output)
|
||||
struct relocation_info *r;
|
||||
long relocation;
|
||||
unsigned char *addr;
|
||||
int relocatable_output;
|
||||
{
|
||||
register unsigned long mask;
|
||||
|
||||
if (relocatable_output) {
|
||||
/*
|
||||
* Non-PC relative relocations which are absolute or
|
||||
* which have become non-external now have fixed
|
||||
* relocations. Set the ADD_EXTRA of this relocation
|
||||
* to be the relocation we have now determined.
|
||||
*/
|
||||
if (!RELOC_PCREL_P(r)) {
|
||||
if ((int) r->r_type <= RELOC_32
|
||||
|| RELOC_EXTERN_P(r) == 0)
|
||||
RELOC_ADD_EXTRA(r) = relocation;
|
||||
} else if (RELOC_EXTERN_P(r))
|
||||
/*
|
||||
* External PC-relative relocations continue
|
||||
* to move around; update their relocations
|
||||
* by the amount they have moved so far.
|
||||
*/
|
||||
RELOC_ADD_EXTRA(r) -= pc_relocation;
|
||||
return;
|
||||
}
|
||||
|
||||
relocation >>= RELOC_VALUE_RIGHTSHIFT(r);
|
||||
|
||||
/* Unshifted mask for relocation */
|
||||
mask = 1 << RELOC_TARGET_BITSIZE(r) - 1;
|
||||
mask |= mask - 1;
|
||||
relocation &= mask;
|
||||
|
||||
/* Shift everything up to where it's going to be used */
|
||||
relocation <<= RELOC_TARGET_BITPOS(r);
|
||||
mask <<= RELOC_TARGET_BITPOS(r);
|
||||
|
||||
switch (RELOC_TARGET_SIZE(r)) {
|
||||
case 0:
|
||||
if (RELOC_MEMORY_ADD_P(r))
|
||||
relocation += (mask & *(u_char *) (addr));
|
||||
*(u_char *) (addr) &= ~mask;
|
||||
*(u_char *) (addr) |= relocation;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (RELOC_MEMORY_ADD_P(r))
|
||||
relocation += (mask & *(u_short *) (addr));
|
||||
*(u_short *) (addr) &= ~mask;
|
||||
*(u_short *) (addr) |= relocation;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (RELOC_MEMORY_ADD_P(r))
|
||||
relocation += (mask & *(u_long *) (addr));
|
||||
*(u_long *) (addr) &= ~mask;
|
||||
*(u_long *) (addr) |= relocation;
|
||||
break;
|
||||
default:
|
||||
fatal( "Unimplemented relocation field length in");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize (output) exec header such that useful values are
|
||||
* obtained from subsequent N_*() macro evaluations.
|
||||
*/
|
||||
void
|
||||
md_init_header(hp, magic, flags)
|
||||
struct exec *hp;
|
||||
int magic, flags;
|
||||
{
|
||||
hp->a_magic = magic;
|
||||
hp->a_machtype = M_SPARC;
|
||||
hp->a_toolversion = 1;
|
||||
hp->a_dynamic = ((flags) & EX_DYNAMIC);
|
||||
|
||||
/* SunOS 4.1 N_TXTADDR depends on the value of outheader.a_entry. */
|
||||
if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */
|
||||
hp->a_entry = N_PAGSIZ(*hp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Machine dependent part of claim_rrs_reloc().
|
||||
* On the Sparc the relocation offsets are stored in the r_addend member.
|
||||
*/
|
||||
int
|
||||
md_make_reloc(rp, r, type)
|
||||
struct relocation_info *rp, *r;
|
||||
int type;
|
||||
{
|
||||
r->r_type = rp->r_type;
|
||||
r->r_addend = rp->r_addend;
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* This wouldn't be strictly necessary - we could record the
|
||||
* location value "in situ" in stead of in the r_addend field -
|
||||
* but we are being Sun compatible here. Besides, Sun's ld.so
|
||||
* has a bug that prevents it from handling this alternate method
|
||||
*/
|
||||
if (RELOC_PCREL_P(rp))
|
||||
r->r_addend -= pc_relocation;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
|
||||
* to the binder slot (which is at offset 0 of the PLT).
|
||||
*/
|
||||
void
|
||||
md_make_jmpslot(sp, offset, index)
|
||||
jmpslot_t *sp;
|
||||
long offset;
|
||||
long index;
|
||||
{
|
||||
u_long fudge = (u_long) -(sizeof(sp->opcode1) + offset);
|
||||
sp->opcode1 = SAVE;
|
||||
/* The following is a RELOC_WDISP30 relocation */
|
||||
sp->opcode2 = CALL | ((fudge >> 2) & 0x3fffffff);
|
||||
sp->reloc_index = NOP | index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a "direct" transfer (ie. not through the run-time binder) from
|
||||
* jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
|
||||
* and by `ld.so' after resolving the symbol.
|
||||
* On the i386, we use the JMP instruction which is PC relative, so no
|
||||
* further RRS relocations will be necessary for such a jmpslot.
|
||||
*
|
||||
* OFFSET unused on Sparc.
|
||||
*/
|
||||
void
|
||||
md_fix_jmpslot(sp, offset, addr)
|
||||
jmpslot_t *sp;
|
||||
long offset;
|
||||
u_long addr;
|
||||
{
|
||||
/*
|
||||
* Here comes a RELOC_{LO10,HI22} relocation pair
|
||||
* The resulting code is:
|
||||
* sethi %hi(addr), %g1
|
||||
* jmp %g1+%lo(addr)
|
||||
* nop ! delay slot
|
||||
*/
|
||||
sp->opcode1 = SETHI | ((addr >> 10) & 0x003fffff);
|
||||
sp->opcode2 = JMP | (addr & 0x000003ff);
|
||||
sp->reloc_index = NOP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the relocation record for a jmpslot.
|
||||
*/
|
||||
void
|
||||
md_make_jmpreloc(rp, r, type)
|
||||
struct relocation_info *rp, *r;
|
||||
int type;
|
||||
{
|
||||
if (type & RELTYPE_RELATIVE)
|
||||
r->r_type = RELOC_RELATIVE;
|
||||
else
|
||||
r->r_type = RELOC_JMP_SLOT;
|
||||
|
||||
r->r_addend = rp->r_addend;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set relocation type for a GOT RRS relocation.
|
||||
*/
|
||||
void
|
||||
md_make_gotreloc(rp, r, type)
|
||||
struct relocation_info *rp, *r;
|
||||
int type;
|
||||
{
|
||||
/*
|
||||
* GOT value resolved (symbolic or entry point): R_32
|
||||
* GOT not resolved: GLOB_DAT
|
||||
*
|
||||
* NOTE: I don't think it makes a difference.
|
||||
*/
|
||||
if (type & RELTYPE_RELATIVE)
|
||||
r->r_type = RELOC_32;
|
||||
else
|
||||
r->r_type = RELOC_GLOB_DAT;
|
||||
|
||||
r->r_addend = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set relocation type for a RRS copy operation.
|
||||
*/
|
||||
void
|
||||
md_make_cpyreloc(rp, r)
|
||||
struct relocation_info *rp, *r;
|
||||
{
|
||||
r->r_type = RELOC_COPY_DAT;
|
||||
r->r_addend = 0;
|
||||
}
|
||||
|
270
gnu/usr.bin/ld/sparc/md.h
Normal file
270
gnu/usr.bin/ld/sparc/md.h
Normal file
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* 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 withough 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: md.h,v 1.3 1993/10/24 00:48:20 pk Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPARC machine dependent definitions
|
||||
*/
|
||||
|
||||
|
||||
#define MAX_ALIGNMENT (sizeof (double))
|
||||
|
||||
#ifdef NetBSD
|
||||
#define PAGSIZ __LDPGSZ
|
||||
|
||||
#define N_SET_FLAG(ex,f) N_SETMAGIC(ex,N_GETMAGIC(ex), \
|
||||
MID_MACHINE, N_GETFLAG(ex)|(f))
|
||||
#define N_IS_DYNAMIC(ex) ((N_GETFLAG(ex) & EX_DYNAMIC))
|
||||
|
||||
#else
|
||||
|
||||
/* Get the SunOS a.out and relocation nomenclature */
|
||||
#define EX_DYNAMIC 1
|
||||
|
||||
#define N_IS_DYNAMIC(ex) ((ex).a_dynamic)
|
||||
|
||||
#define N_SET_FLAG(ex, f) { \
|
||||
(ex).a_dynamic = ((f) & EX_DYNAMIC); \
|
||||
}
|
||||
|
||||
#undef relocation_info
|
||||
#define relocation_info reloc_info_sparc
|
||||
#define r_symbolnum r_index
|
||||
#endif /* NetBSD */
|
||||
|
||||
/* Sparc (Sun 4) macros */
|
||||
#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
|
||||
#ifdef RTLD
|
||||
/* XXX - consider this making SUN_COMPAT --> repercussions on rrs.c */
|
||||
#define RELOC_MEMORY_ADD_P(r) 1
|
||||
#else
|
||||
#define RELOC_MEMORY_ADD_P(r) 0
|
||||
#endif
|
||||
#define RELOC_ADD_EXTRA(r) ((r)->r_addend)
|
||||
#define RELOC_PCREL_P(r) \
|
||||
(((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) \
|
||||
|| ((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22) \
|
||||
|| (r)->r_type == RELOC_JMP_TBL)
|
||||
#define RELOC_VALUE_RIGHTSHIFT(r) (reloc_target_rightshift[(r)->r_type])
|
||||
#define RELOC_TARGET_SIZE(r) (reloc_target_size[(r)->r_type])
|
||||
#define RELOC_TARGET_BITPOS(r) 0
|
||||
#define RELOC_TARGET_BITSIZE(r) (reloc_target_bitsize[(r)->r_type])
|
||||
|
||||
#define RELOC_JMPTAB_P(r) ((r)->r_type == RELOC_JMP_TBL)
|
||||
|
||||
#define RELOC_BASEREL_P(r) \
|
||||
((r)->r_type >= RELOC_BASE10 && (r)->r_type <= RELOC_BASE22)
|
||||
|
||||
#define RELOC_RELATIVE_P(r) ((r)->r_type == RELOC_RELATIVE)
|
||||
#define RELOC_COPY_DAT (RELOC_RELATIVE+1) /*XXX*/
|
||||
#define RELOC_COPY_P(r) ((r)->r_type == RELOC_COPY_DAT)
|
||||
#define RELOC_LAZY_P(r) ((r)->r_type == RELOC_JMP_SLOT)
|
||||
|
||||
#define RELOC_STATICS_THROUGH_GOT_P(r) (1)
|
||||
#define JMPSLOT_NEEDS_RELOC (1)
|
||||
|
||||
#define CHECK_GOT_RELOC(r) \
|
||||
((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22)
|
||||
|
||||
#define md_got_reloc(r) (-(r)->r_address)
|
||||
|
||||
#ifdef SUN_COMPAT
|
||||
/*
|
||||
* Sun plays games with `r_addend'
|
||||
*/
|
||||
#define md_get_rt_segment_addend(r,a) (0)
|
||||
#endif
|
||||
|
||||
/* Width of a Global Offset Table entry */
|
||||
typedef long got_t;
|
||||
|
||||
typedef struct jmpslot {
|
||||
u_long opcode1;
|
||||
u_long opcode2;
|
||||
u_long reloc_index;
|
||||
#define JMPSLOT_RELOC_MASK (0x003fffff) /* 22 bits */
|
||||
} jmpslot_t;
|
||||
|
||||
#define SAVE 0x9de3bfa0 /* Build stack frame (opcode1) */
|
||||
#define SETHI 0x03000000 /* %hi(addr) -> %g1 (opcode1) */
|
||||
#define CALL 0x40000000 /* Call instruction (opcode2) */
|
||||
#define JMP 0x81c06000 /* Jump %g1 instruction (opcode2) */
|
||||
#define NOP 0x01000000 /* Delay slot NOP for (reloc_index) */
|
||||
|
||||
|
||||
/*
|
||||
* Byte swap defs for cross linking
|
||||
*/
|
||||
|
||||
#if !defined(NEED_SWAP)
|
||||
|
||||
#define md_swapin_exec_hdr(h)
|
||||
#define md_swapout_exec_hdr(h)
|
||||
#define md_swapin_symbols(s,n)
|
||||
#define md_swapout_symbols(s,n)
|
||||
#define md_swapin_zsymbols(s,n)
|
||||
#define md_swapout_zsymbols(s,n)
|
||||
#define md_swapin_reloc(r,n)
|
||||
#define md_swapout_reloc(r,n)
|
||||
#define md_swapin_link_dynamic(l)
|
||||
#define md_swapout_link_dynamic(l)
|
||||
#define md_swapin_link_dynamic_2(l)
|
||||
#define md_swapout_link_dynamic_2(l)
|
||||
#define md_swapin_ld_debug(d)
|
||||
#define md_swapout_ld_debug(d)
|
||||
#define md_swapin_rrs_hash(f,n)
|
||||
#define md_swapout_rrs_hash(f,n)
|
||||
#define md_swapin_link_object(l,n)
|
||||
#define md_swapout_link_object(l,n)
|
||||
#define md_swapout_jmpslot(j,n)
|
||||
#define md_swapout_got(g,n)
|
||||
#define md_swapin_ranlib_hdr(h,n)
|
||||
#define md_swapout_ranlib_hdr(h,n)
|
||||
|
||||
#endif /* NEED_SWAP */
|
||||
|
||||
#ifdef CROSS_LINKER
|
||||
|
||||
#ifdef NEED_SWAP
|
||||
|
||||
/* Define IO byte swapping routines */
|
||||
|
||||
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));
|
||||
|
||||
#define md_swapin_symbols(s,n) swap_symbols(s,n)
|
||||
#define md_swapout_symbols(s,n) swap_symbols(s,n)
|
||||
#define md_swapin_zsymbols(s,n) swap_zsymbols(s,n)
|
||||
#define md_swapout_zsymbols(s,n) swap_zsymbols(s,n)
|
||||
#define md_swapin_link_dynamic(l) swap_link_dynamic(l)
|
||||
#define md_swapout_link_dynamic(l) swap_link_dynamic(l)
|
||||
#define md_swapin_link_dynamic_2(l) swap_link_dynamic_2(l)
|
||||
#define md_swapout_link_dynamic_2(l) swap_link_dynamic_2(l)
|
||||
#define md_swapin_ld_debug(d) swap_ld_debug(d)
|
||||
#define md_swapout_ld_debug(d) swap_ld_debug(d)
|
||||
#define md_swapin_rrs_hash(f,n) swap_rrs_hash(f,n)
|
||||
#define md_swapout_rrs_hash(f,n) swap_rrs_hash(f,n)
|
||||
#define md_swapin_link_object(l,n) swapin_link_object(l,n)
|
||||
#define md_swapout_link_object(l,n) swapout_link_object(l,n)
|
||||
#define md_swapout_got(g,n) swap_longs((long*)(g),n)
|
||||
#define md_swapin_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
|
||||
#define md_swapout_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
|
||||
|
||||
#define md_swap_short(x) ( (((x) >> 8) & 0xff) | (((x) & 0xff) << 8) )
|
||||
|
||||
#define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \
|
||||
(((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000))
|
||||
|
||||
#define get_byte(p) ( ((unsigned char *)(p))[0] )
|
||||
|
||||
#define get_short(p) ( ( ((unsigned char *)(p))[1] << 8) | \
|
||||
( ((unsigned char *)(p))[0] ) \
|
||||
)
|
||||
#define get_long(p) ( ( ((unsigned char *)(p))[3] << 24) | \
|
||||
( ((unsigned char *)(p))[2] << 16) | \
|
||||
( ((unsigned char *)(p))[1] << 8 ) | \
|
||||
( ((unsigned char *)(p))[0] ) \
|
||||
)
|
||||
|
||||
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
|
||||
|
||||
#define put_short(p, v) { ((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#define put_long(p, v) { ((unsigned char *)(p))[3] = \
|
||||
((((unsigned long)(v)) >> 24) & 0xff); \
|
||||
((unsigned char *)(p))[2] = \
|
||||
((((unsigned long)(v)) >> 16) & 0xff); \
|
||||
((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#else /* We need not swap, but must pay attention to alignment: */
|
||||
|
||||
#define md_swap_short(x) (x)
|
||||
#define md_swap_long(x) (x)
|
||||
|
||||
#define get_byte(p) ( ((unsigned char *)(p))[0] )
|
||||
|
||||
#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \
|
||||
( ((unsigned char *)(p))[1] ) \
|
||||
)
|
||||
|
||||
#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \
|
||||
( ((unsigned char *)(p))[1] << 16) | \
|
||||
( ((unsigned char *)(p))[2] << 8 ) | \
|
||||
( ((unsigned char *)(p))[3] ) \
|
||||
)
|
||||
|
||||
|
||||
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
|
||||
|
||||
#define put_short(p, v) { ((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#define put_long(p, v) { ((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) >> 24) & 0xff); \
|
||||
((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) >> 16) & 0xff); \
|
||||
((unsigned char *)(p))[2] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[3] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#endif /* NEED_SWAP */
|
||||
|
||||
#else /* Not a cross linker: use native */
|
||||
|
||||
#define md_swap_short(x) (x)
|
||||
#define md_swap_long(x) (x)
|
||||
|
||||
#define get_byte(where) (*(char *)(where))
|
||||
#define get_short(where) (*(short *)(where))
|
||||
#define get_long(where) (*(long *)(where))
|
||||
|
||||
#define put_byte(where,what) (*(char *)(where) = (what))
|
||||
#define put_short(where,what) (*(short *)(where) = (what))
|
||||
#define put_long(where,what) (*(long *)(where) = (what))
|
||||
|
||||
#endif /* CROSS_LINKER */
|
||||
|
101
gnu/usr.bin/ld/sparc/mdprologue.S
Normal file
101
gnu/usr.bin/ld/sparc/mdprologue.S
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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 withough 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: mdprologue.S,v 1.1 1993/10/16 21:54:36 pk Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPARC run-time link editor entry points.
|
||||
*/
|
||||
|
||||
#define CRT_VERSION_SUN 1
|
||||
|
||||
.seg "text" ! [internal]
|
||||
.proc 16
|
||||
.global _rtld_entry
|
||||
_rtld_entry:
|
||||
!#PROLOGUE# 0
|
||||
save %sp,-96,%sp
|
||||
L.1B:
|
||||
call L.2B
|
||||
sethi %hi((__GLOBAL_OFFSET_TABLE_-(L.1B-.))),%l7
|
||||
L.2B:
|
||||
!#PROLOGUE# 1
|
||||
or %l7,%lo((__GLOBAL_OFFSET_TABLE_-(L.1B-.))),%l7
|
||||
add %l7,%o7,%l7
|
||||
|
||||
cmp %i0, CRT_VERSION_SUN ! is crtp passed in Sun style,
|
||||
bne 1f ! ie. relative to stack frame ?
|
||||
nop
|
||||
add %i1, %fp, %i1 ! if so, adjust to absolute address
|
||||
1:
|
||||
ld [%i1], %o3 ! load base address (crtp->crt_ba)
|
||||
ld [%l7], %o2 ! get rtld's __DYNAMIC address
|
||||
! from 1st GOT entry
|
||||
add %o2, %o3, %o2 ! relocate and make it 3rd arg.
|
||||
|
||||
ld [%l7 + _rtld], %g1 ! get address of rtld()
|
||||
add %g1, %o3, %g1 ! relocate
|
||||
|
||||
mov %i1, %o1 ! set up args, #2: crtp
|
||||
call %g1 ! rtld(version, crtp, dp)
|
||||
mov %i0, %o0 ! arg #1: version
|
||||
|
||||
ret
|
||||
restore
|
||||
.seg "data" ! [internal]
|
||||
|
||||
.seg "text"
|
||||
.global _binder_entry
|
||||
_binder_entry:
|
||||
!#PROLOGUE# 0
|
||||
save %sp,-96,%sp
|
||||
!L.1C:
|
||||
! call L.2C
|
||||
! sethi %hi((__GLOBAL_OFFSET_TABLE_-(L.1C-.))),%l7
|
||||
!L.2C:
|
||||
! or %l7,%lo((__GLOBAL_OFFSET_TABLE_-(L.1C-.))),%l7
|
||||
!#PROLOGUE# 1
|
||||
|
||||
sub %i7, 4, %o0 ! get to jmpslot through pc
|
||||
ld [%i7+4], %o1 ! get relocation index
|
||||
sethi %hi(0x3fffff), %o2 ! -> reloc_index & 0x003fffff
|
||||
or %o2, %lo(0x3fffff), %o2 ! [internal]
|
||||
call _binder ! and call binder(jsp, reloc_index)
|
||||
and %o1, %o2, %o1
|
||||
|
||||
mov %o0, %g1 ! return value == function address
|
||||
|
||||
restore ! get rid of our context
|
||||
jmp %g1 ! and go.
|
||||
restore ! and the jmpslot's
|
||||
nop
|
||||
|
||||
.seg "data" ! [internal]
|
||||
|
148
gnu/usr.bin/ld/symbol.c
Normal file
148
gnu/usr.bin/ld/symbol.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* $Id: symbol.c,v 1.3 1993/11/01 16:26:19 pk Exp $ - symbol table routines
|
||||
*/
|
||||
|
||||
/* Create the symbol table entries for `etext', `edata' and `end'. */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
void
|
||||
symtab_init (relocatable_output)
|
||||
int relocatable_output;
|
||||
{
|
||||
/*
|
||||
* Put linker reserved symbols into symbol table.
|
||||
*/
|
||||
|
||||
dynamic_symbol = getsym ("__DYNAMIC");
|
||||
dynamic_symbol->defined = relocatable_output?N_UNDF:(N_DATA | N_EXT);
|
||||
dynamic_symbol->referenced = 0;
|
||||
dynamic_symbol->value = 0;
|
||||
|
||||
got_symbol = getsym ("__GLOBAL_OFFSET_TABLE_");
|
||||
got_symbol->defined = N_DATA | N_EXT;
|
||||
got_symbol->referenced = 0;
|
||||
got_symbol->value = 0;
|
||||
|
||||
if (relocatable_output)
|
||||
return;
|
||||
|
||||
#ifndef nounderscore
|
||||
edata_symbol = getsym ("_edata");
|
||||
etext_symbol = getsym ("_etext");
|
||||
end_symbol = getsym ("_end");
|
||||
#else
|
||||
edata_symbol = getsym ("edata");
|
||||
etext_symbol = getsym ("etext");
|
||||
end_symbol = getsym ("end");
|
||||
#endif
|
||||
edata_symbol->defined = N_DATA | N_EXT;
|
||||
etext_symbol->defined = N_TEXT | N_EXT;
|
||||
end_symbol->defined = N_BSS | N_EXT;
|
||||
|
||||
edata_symbol->referenced = 1;
|
||||
etext_symbol->referenced = 1;
|
||||
end_symbol->referenced = 1;
|
||||
}
|
||||
|
||||
/* 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) % TABSIZE;
|
||||
|
||||
/* Search the bucket. */
|
||||
for (bp = symtab[hashval]; bp; bp = bp->link)
|
||||
if (! strcmp (key, bp->name))
|
||||
return bp;
|
||||
|
||||
/* Nothing was found; create a new symbol table entry. */
|
||||
bp = (symbol *) xmalloc (sizeof (symbol));
|
||||
bp->refs = 0;
|
||||
bp->name = (char *) xmalloc (strlen (key) + 1);
|
||||
strcpy (bp->name, key);
|
||||
bp->defined = 0;
|
||||
bp->referenced = 0;
|
||||
bp->trace = 0;
|
||||
bp->value = 0;
|
||||
bp->max_common_size = 0;
|
||||
bp->warning = 0;
|
||||
bp->undef_refs = 0;
|
||||
bp->multiply_defined = 0;
|
||||
bp->alias = 0;
|
||||
bp->setv_count = 0;
|
||||
|
||||
bp->size = 0;
|
||||
bp->sorefs = 0;
|
||||
bp->so_defined = 0;
|
||||
bp->def_nlist = 0;
|
||||
bp->jmpslot_offset = -1;
|
||||
bp->gotslot_offset = -1;
|
||||
bp->jmpslot_claimed = 0;
|
||||
bp->gotslot_claimed = 0;
|
||||
bp->cpyreloc_reserved = 0;
|
||||
bp->cpyreloc_claimed = 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) % TABSIZE;
|
||||
|
||||
/* Search the bucket. */
|
||||
|
||||
for (bp = symtab[hashval]; bp; bp = bp->link)
|
||||
if (! strcmp (key, bp->name))
|
||||
return bp;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -3,7 +3,8 @@
|
|||
* This code is derived from software copyrighted by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* @(#)symseg.h 5.4 (Berkeley) 4/30/91
|
||||
* from: @(#)symseg.h 5.4 (Berkeley) 4/30/91
|
||||
* $Id: symseg.h,v 1.2 1993/08/01 18:46:59 mycroft Exp $
|
||||
*/
|
||||
|
||||
/* GDB symbol table format definitions.
|
||||
|
|
755
gnu/usr.bin/ld/warnings.c
Normal file
755
gnu/usr.bin/ld/warnings.c
Normal file
|
@ -0,0 +1,755 @@
|
|||
/*
|
||||
* $Id: warnings.c,v 1.3 1993/11/01 16:26:20 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.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"
|
||||
|
||||
/*
|
||||
* 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->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->superfile) {
|
||||
supfile = get_file_name (entry->superfile);
|
||||
result = (char *) xmalloc (strlen(supfile)
|
||||
+ strlen(entry->filename) + 3);
|
||||
sprintf (result, "%s(%s)", supfile, entry->filename);
|
||||
free (supfile);
|
||||
|
||||
} else {
|
||||
result = (char *) xmalloc (strlen (entry->filename) + 1);
|
||||
strcpy (result, entry->filename);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Report a fatal error. The error message is STRING followed by the
|
||||
* filename of ENTRY.
|
||||
*/
|
||||
void
|
||||
#if __STDC__
|
||||
fatal_with_file (char *fmt, struct file_entry *entry, ...)
|
||||
#else
|
||||
fatal_with_file (fmt, entry, va_alist)
|
||||
char *fmt;
|
||||
struct file_entry *entry;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
(void)fprintf(stderr, "%s: ", progname);
|
||||
(void)vfprintf(stderr, fmt, ap);
|
||||
print_file_name (entry, stderr);
|
||||
(void)fprintf(stderr, "\n");
|
||||
|
||||
va_end(ap);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Report a fatal error using the message for the last failed system call,
|
||||
* followed by the string NAME.
|
||||
*/
|
||||
void
|
||||
perror_name (name)
|
||||
char *name;
|
||||
{
|
||||
extern int errno, sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
char *s;
|
||||
|
||||
if (errno < sys_nerr)
|
||||
s = concat ("", sys_errlist[errno], " for %s");
|
||||
else
|
||||
s = "cannot open %s";
|
||||
fatal (s, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Report a fatal error using the message for the last failed system call,
|
||||
* followed by the name of file ENTRY.
|
||||
*/
|
||||
void
|
||||
perror_file (entry)
|
||||
struct file_entry *entry;
|
||||
{
|
||||
extern int errno, sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
char *s;
|
||||
|
||||
if (errno < sys_nerr)
|
||||
s = concat ("", sys_errlist[errno], " for ");
|
||||
else
|
||||
s = "cannot open ";
|
||||
fatal_with_file (s, entry);
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
{
|
||||
register int i;
|
||||
|
||||
fprintf(outfile, "\nFiles:\n\n");
|
||||
|
||||
each_file(describe_file_sections, outfile);
|
||||
|
||||
fprintf(outfile, "\nGlobal symbols:\n\n");
|
||||
|
||||
for (i = 0; i < TABSIZE; i++) {
|
||||
register symbol *sp;
|
||||
for (sp = symtab[i]; sp; sp = sp->link) {
|
||||
if (sp->defined == 1)
|
||||
fprintf(outfile, " %s: common, length %#x\n",
|
||||
sp->name, sp->max_common_size);
|
||||
if ( sp->referenced) {
|
||||
if (sp->defined)
|
||||
fprintf(outfile, " %s: %#x %#x\n",
|
||||
sp->name, sp->value, sp->size);
|
||||
else
|
||||
fprintf(outfile, " %s: undefined\n",
|
||||
sp->name);
|
||||
} else
|
||||
fprintf(outfile, " %s: unreferenced\n",
|
||||
sp->name);
|
||||
}
|
||||
}
|
||||
|
||||
each_file(list_file_locals, outfile);
|
||||
}
|
||||
|
||||
static void
|
||||
describe_file_sections(entry, outfile)
|
||||
struct file_entry *entry;
|
||||
FILE *outfile;
|
||||
{
|
||||
fprintf(outfile, " ");
|
||||
print_file_name(entry, outfile);
|
||||
if (entry->just_syms_flag)
|
||||
fprintf(outfile, " symbols only\n", 0);
|
||||
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_warning_symbols; /* List warning syms */
|
||||
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
|
||||
relocation_entries_relation (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 *endp = entry->symbols + entry->nsymbols;
|
||||
|
||||
|
||||
current->sym = next->sym;
|
||||
current->line = next->line;
|
||||
current->filename = next->filename;
|
||||
|
||||
while (++(next->sym) < endp) {
|
||||
|
||||
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;
|
||||
{
|
||||
struct localsymbol *lsp;
|
||||
struct line_debug_entry *state_pointer = (struct line_debug_entry *)
|
||||
xmalloc(3 * sizeof(struct line_debug_entry));
|
||||
|
||||
register struct line_debug_entry
|
||||
*current = state_pointer,
|
||||
*next = state_pointer + 1,
|
||||
*source = state_pointer + 2; /* Used to store source file */
|
||||
|
||||
|
||||
for (lsp = entry->symbols; lsp < entry->symbols+entry->nsymbols; lsp++)
|
||||
if (lsp->nzlist.nlist.n_type == N_SO)
|
||||
break;
|
||||
|
||||
if (lsp >= entry->symbols + entry->nsymbols) {
|
||||
/* 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 = state_pointer, *next = state_pointer + 1;
|
||||
struct line_debug_entry *tmp_pointer;
|
||||
|
||||
int use_data_symbols;
|
||||
|
||||
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 *reloc, *reloc_start =
|
||||
data_segment ? entry->datarel : entry->textrel;
|
||||
|
||||
int reloc_size = (data_segment ? entry->ndatarel : entry->ntextrel);
|
||||
int start_of_segment = (data_segment ?
|
||||
entry->data_start_address :
|
||||
entry->text_start_address);
|
||||
struct localsymbol *start_of_syms = entry->symbols;
|
||||
struct line_debug_entry *state_pointer =
|
||||
init_debug_scan(data_segment != 0, entry);
|
||||
|
||||
register struct line_debug_entry *current = state_pointer;
|
||||
|
||||
/* 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;
|
||||
|
||||
/*
|
||||
* We need to sort the relocation info here. Sheesh, so much effort
|
||||
* for one lousy error optimization.
|
||||
*/
|
||||
|
||||
qsort(reloc_start, reloc_size, sizeof(struct relocation_info),
|
||||
relocation_entries_relation);
|
||||
|
||||
for (reloc = reloc_start;
|
||||
reloc < (reloc_start + reloc_size);
|
||||
reloc++) {
|
||||
register struct localsymbol *s;
|
||||
register symbol *g;
|
||||
|
||||
/*
|
||||
* If the relocation isn't resolved through a symbol,
|
||||
* continue
|
||||
*/
|
||||
if (!RELOC_EXTERN_P(reloc))
|
||||
continue;
|
||||
|
||||
s = &entry->symbols[RELOC_SYMBOL(reloc)];
|
||||
|
||||
/*
|
||||
* 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 (!(s->nzlist.nz_type & N_EXT))
|
||||
continue;
|
||||
|
||||
g = s->symbol;
|
||||
errmsg = 0;
|
||||
|
||||
if (!g->defined && !g->so_defined && list_unresolved_refs) { /* Reference */
|
||||
/* Mark as being noted by relocation warning pass. */
|
||||
SET_BIT(nlist_bitvector, s - start_of_syms);
|
||||
|
||||
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;
|
||||
|
||||
/* Mark as being noted by relocation warning pass. */
|
||||
SET_BIT(nlist_bitvector, s - 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(reloc) + 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 number_of_syms = entry->nsymbols;
|
||||
unsigned char *nlist_bitvector = (unsigned char *)
|
||||
alloca ((number_of_syms >> 3) + 1);
|
||||
struct line_debug_entry *text_scan, *data_scan;
|
||||
int i;
|
||||
char *errfmt, *file_name;
|
||||
int line_number;
|
||||
int dont_allow_symbol_name;
|
||||
|
||||
bzero (nlist_bitvector, (number_of_syms >> 3) + 1);
|
||||
|
||||
/* Read in the files strings if they aren't available */
|
||||
if (!entry->strings) {
|
||||
int desc;
|
||||
|
||||
entry->strings = (char *) alloca (entry->string_size);
|
||||
desc = file_open (entry);
|
||||
read_entry_strings (desc, entry);
|
||||
}
|
||||
|
||||
if (! entry->is_dynamic) {
|
||||
/* Do text warnings based on a scan through the relocation info. */
|
||||
do_relocation_warnings (entry, 0, outfile, nlist_bitvector);
|
||||
|
||||
/* Do data warnings based on a scan through the relocation 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 < number_of_syms; i++) {
|
||||
struct nlist *s;
|
||||
struct glosym *g;
|
||||
|
||||
g = entry->symbols[i].symbol;
|
||||
s = &entry->symbols[i].nzlist.nlist;
|
||||
|
||||
if (!(s->n_type & N_EXT))
|
||||
continue;
|
||||
|
||||
if (!g->referenced) {
|
||||
#if 0
|
||||
/* Check for undefined shobj symbols */
|
||||
struct localsymbol *lsp;
|
||||
register int type;
|
||||
|
||||
for (lsp = g->dynrefs; lsp; lsp = lsp->next) {
|
||||
type = lsp->nlist.n_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;
|
||||
}
|
||||
|
||||
if (undefined_global_sym_count == 0)
|
||||
/* No undefined symbols in rel files */
|
||||
continue;
|
||||
|
||||
dont_allow_symbol_name = 0;
|
||||
|
||||
if (list_multiple_defs && g->multiply_defined) {
|
||||
errfmt = "Definition of symbol %s (multiply defined)";
|
||||
switch (s->n_type) {
|
||||
case N_TEXT | N_EXT:
|
||||
line_number = address_to_line (s->n_value, text_scan);
|
||||
file_name = text_scan[0].filename;
|
||||
break;
|
||||
case N_DATA | N_EXT:
|
||||
line_number = address_to_line (s->n_value, data_scan);
|
||||
file_name = data_scan[0].filename;
|
||||
break;
|
||||
#if 0
|
||||
case N_SETA | N_EXT:
|
||||
case N_SETT | N_EXT:
|
||||
case N_SETD | N_EXT:
|
||||
case N_SETB | N_EXT:
|
||||
if (g->multiply_defined == 2)
|
||||
continue;
|
||||
errfmt = "First set element definition of symbol %s (multiply defined)";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Don't print out multiple defs
|
||||
at references.*/
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (BIT_SET_P (nlist_bitvector, i))
|
||||
continue;
|
||||
else if (list_unresolved_refs && !g->defined) {
|
||||
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->warning) {
|
||||
/*
|
||||
* There are two cases in which we don't want to do
|
||||
* this. The first is if this is a definition instead
|
||||
* do a reference. The second is if it's the reference
|
||||
* used by the warning stabs itself.
|
||||
*/
|
||||
if (s->n_type != (N_EXT | N_UNDF)
|
||||
|| (i && (s-1)->n_type == N_WARNING))
|
||||
continue;
|
||||
|
||||
errfmt = g->warning;
|
||||
line_number = -1;
|
||||
dont_allow_symbol_name = 1;
|
||||
} else
|
||||
continue;
|
||||
|
||||
if (line_number == -1)
|
||||
fprintf (outfile, "%s: ", entry->filename);
|
||||
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 dissapear anyway. */
|
||||
}
|
||||
|
||||
int
|
||||
do_warnings(outfile)
|
||||
FILE *outfile;
|
||||
{
|
||||
list_unresolved_refs = !relocatable_output &&
|
||||
(undefined_global_sym_count || undefined_shobj_sym_count);
|
||||
list_warning_symbols = warning_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, outfile);
|
||||
|
||||
if (list_unresolved_refs || list_multiple_defs)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
166
gnu/usr.bin/ld/xbits.c
Normal file
166
gnu/usr.bin/ld/xbits.c
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* 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 withough 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.1 1993/10/16 21:52:37 pk 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_link_dynamic(dp)
|
||||
struct link_dynamic *dp;
|
||||
{
|
||||
dp->ld_version = md_swap_long(dp->ld_version);
|
||||
dp->ldd = (struct ld_debug *)md_swap_long((long)dp->ldd);
|
||||
dp->ld_un.ld_2 = (struct link_dynamic_2 *)md_swap_long((long)dp->ld_un.ld_2);
|
||||
dp->ld_entry = (struct ld_entry *)md_swap_long((long)dp->ld_entry);
|
||||
}
|
||||
|
||||
void
|
||||
swap_link_dynamic_2(ldp)
|
||||
struct link_dynamic_2 *ldp;
|
||||
{
|
||||
swap_longs((long *)ldp, sizeof(*ldp)/sizeof(long));
|
||||
}
|
||||
|
||||
void
|
||||
swap_ld_debug(lddp)
|
||||
struct ld_debug *lddp;
|
||||
{
|
||||
swap_longs((long *)lddp, sizeof(*lddp)/sizeof(long));
|
||||
}
|
||||
|
||||
void
|
||||
swapin_link_object(lop, n)
|
||||
struct link_object *lop;
|
||||
int n;
|
||||
{
|
||||
unsigned long bits;
|
||||
|
||||
for (; n; n--, lop++) {
|
||||
lop->lo_name = md_swap_long(lop->lo_name);
|
||||
lop->lo_major = md_swap_short(lop->lo_major);
|
||||
lop->lo_minor = md_swap_short(lop->lo_minor);
|
||||
lop->lo_next = md_swap_long(lop->lo_next);
|
||||
bits = ((unsigned long *)lop)[1];
|
||||
lop->lo_library = ((bits >> 24) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
swapout_link_object(lop, n)
|
||||
struct link_object *lop;
|
||||
int n;
|
||||
{
|
||||
unsigned long bits;
|
||||
|
||||
for (; n; n--, lop++) {
|
||||
lop->lo_name = md_swap_long(lop->lo_name);
|
||||
lop->lo_major = md_swap_short(lop->lo_major);
|
||||
lop->lo_minor = md_swap_short(lop->lo_minor);
|
||||
lop->lo_next = md_swap_long(lop->lo_next);
|
||||
bits = (unsigned long)(lop->lo_library) << 24;
|
||||
((unsigned long *)lop)[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);
|
||||
}
|
||||
}
|
||||
|
24
libexec/rtld-aout/Makefile
Normal file
24
libexec/rtld-aout/Makefile
Normal file
|
@ -0,0 +1,24 @@
|
|||
# $Id: Makefile,v 1.2 1993/10/27 00:55:24 pk Exp $
|
||||
|
||||
PROG= ld.so
|
||||
SRCS= mdprologue.S rtld.c shlib.c etc.c md.c
|
||||
NOMAN= noman
|
||||
LDDIR?= $(.CURDIR)/..
|
||||
#PICFLAG=-pic
|
||||
PICFLAG=-fpic
|
||||
CFLAGS += -I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) -O $(PICFLAG) -DRTLD
|
||||
LDFLAGS = -Bshareable -Bsymbolic -assert nosymbolic
|
||||
LIBS = -lc_pic
|
||||
BINDIR= /usr/libexec
|
||||
|
||||
.PATH: $(LDDIR) $(LDDIR)/$(MACHINE)
|
||||
|
||||
.SUFFIXES: .S
|
||||
|
||||
$(PROG):
|
||||
$(LD) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIBS)
|
||||
|
||||
.S.o:
|
||||
$(CPP) $(.IMPSRC) | $(AS) -k -o $(.TARGET) -
|
||||
|
||||
.include <bsd.prog.mk>
|
15
libexec/rtld-aout/i386/md-static-funcs.c
Normal file
15
libexec/rtld-aout/i386/md-static-funcs.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
/*
|
||||
* Called by ld.so when onanating.
|
||||
* This *must* be a static function, so it is not called through a jmpslot.
|
||||
*/
|
||||
static void
|
||||
md_relocate_simple(r, relocation, addr)
|
||||
struct relocation_info *r;
|
||||
long relocation;
|
||||
char *addr;
|
||||
{
|
||||
if (r->r_relative)
|
||||
*(long *)addr += relocation;
|
||||
}
|
||||
|
329
libexec/rtld-aout/i386/md.c
Normal file
329
libexec/rtld-aout/i386/md.c
Normal file
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* 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 withough 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: md.c,v 1.2 1993/10/27 00:54:58 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
/*
|
||||
* Get relocation addend corresponding to relocation record RP
|
||||
* from address ADDR
|
||||
*/
|
||||
long
|
||||
md_get_addend(rp, addr)
|
||||
struct relocation_info *rp;
|
||||
unsigned char *addr;
|
||||
{
|
||||
switch (RELOC_TARGET_SIZE(rp)) {
|
||||
case 0:
|
||||
return get_byte(addr);
|
||||
break;
|
||||
case 1:
|
||||
return get_short(addr);
|
||||
break;
|
||||
case 2:
|
||||
return get_long(addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Put RELOCATION at ADDR according to relocation record RP.
|
||||
*/
|
||||
void
|
||||
md_relocate(rp, relocation, addr, relocatable_output)
|
||||
struct relocation_info *rp;
|
||||
long relocation;
|
||||
unsigned char *addr;
|
||||
{
|
||||
switch (RELOC_TARGET_SIZE(rp)) {
|
||||
case 0:
|
||||
put_byte(addr, relocation);
|
||||
break;
|
||||
case 1:
|
||||
put_short(addr, relocation);
|
||||
break;
|
||||
case 2:
|
||||
put_long(addr, relocation);
|
||||
break;
|
||||
default:
|
||||
fatal("Unsupported relocation size: %x", RELOC_TARGET_SIZE(rp));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize (output) exec header such that useful values are
|
||||
* obtained from subsequent N_*() macro evaluations.
|
||||
*/
|
||||
void
|
||||
md_init_header(hp, magic, flags)
|
||||
struct exec *hp;
|
||||
int magic, flags;
|
||||
{
|
||||
N_SETMAGIC((*hp), magic, MID_I386, flags);
|
||||
|
||||
/* TEXT_START depends on the value of outheader.a_entry. */
|
||||
if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */
|
||||
hp->a_entry = PAGSIZ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Machine dependent part of claim_rrs_reloc().
|
||||
* Set RRS relocation type.
|
||||
*/
|
||||
int
|
||||
md_make_reloc(rp, r, type)
|
||||
struct relocation_info *rp, *r;
|
||||
int type;
|
||||
{
|
||||
/* Relocation size */
|
||||
r->r_length = rp->r_length;
|
||||
|
||||
if (RELOC_PCREL_P(rp))
|
||||
r->r_pcrel = 1;
|
||||
|
||||
if (type & RELTYPE_RELATIVE)
|
||||
r->r_relative = 1;
|
||||
|
||||
if (type & RELTYPE_COPY)
|
||||
r->r_copy = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
|
||||
* to the binder slot (which is at offset 0 of the PLT).
|
||||
*/
|
||||
void
|
||||
md_make_jmpslot(sp, offset, index)
|
||||
jmpslot_t *sp;
|
||||
long offset;
|
||||
long index;
|
||||
{
|
||||
/*
|
||||
* i386 PC-relative "fixed point" is located right after the
|
||||
* instruction it pertains to.
|
||||
*/
|
||||
u_long fudge = - (sizeof(sp->opcode) + sizeof(sp->addr) + offset);
|
||||
|
||||
sp->opcode = CALL;
|
||||
#if 0
|
||||
sp->addr = fudge;
|
||||
#else
|
||||
sp->addr[0] = fudge & 0xffff;
|
||||
sp->addr[1] = fudge >> 16;
|
||||
#endif
|
||||
sp->reloc_index = index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a "direct" transfer (ie. not through the run-time binder) from
|
||||
* jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
|
||||
* and by `ld.so' after resolving the symbol.
|
||||
* On the i386, we use the JMP instruction which is PC relative, so no
|
||||
* further RRS relocations will be necessary for such a jmpslot.
|
||||
*/
|
||||
void
|
||||
md_fix_jmpslot(sp, offset, addr)
|
||||
jmpslot_t *sp;
|
||||
long offset;
|
||||
u_long addr;
|
||||
{
|
||||
u_long fudge = addr - (sizeof(sp->opcode) + sizeof(sp->addr) + offset);
|
||||
|
||||
sp->opcode = JUMP;
|
||||
#if 0
|
||||
sp->addr = fudge;
|
||||
#else
|
||||
sp->addr[0] = fudge & 0xffff;
|
||||
sp->addr[1] = fudge >> 16;
|
||||
#endif
|
||||
sp->reloc_index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the relocation record for a RRS jmpslot.
|
||||
*/
|
||||
void
|
||||
md_make_jmpreloc(rp, r, type)
|
||||
struct relocation_info *rp, *r;
|
||||
int type;
|
||||
{
|
||||
jmpslot_t *sp;
|
||||
|
||||
/*
|
||||
* Fix relocation address to point to the correct
|
||||
* location within this jmpslot.
|
||||
*/
|
||||
r->r_address += sizeof(sp->opcode);
|
||||
|
||||
/* Relocation size */
|
||||
r->r_length = 2;
|
||||
|
||||
/* Set relocation type */
|
||||
r->r_jmptable = 1;
|
||||
if (type & RELTYPE_RELATIVE)
|
||||
r->r_relative = 1;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Set relocation type for a RRS GOT relocation.
|
||||
*/
|
||||
void
|
||||
md_make_gotreloc(rp, r, type)
|
||||
struct relocation_info *rp, *r;
|
||||
int type;
|
||||
{
|
||||
r->r_baserel = 1;
|
||||
if (type & RELTYPE_RELATIVE)
|
||||
r->r_relative = 1;
|
||||
|
||||
/* Relocation size */
|
||||
r->r_length = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set relocation type for a RRS copy operation.
|
||||
*/
|
||||
void
|
||||
md_make_cpyreloc(rp, r)
|
||||
struct relocation_info *rp, *r;
|
||||
{
|
||||
/* Relocation size */
|
||||
r->r_length = 2;
|
||||
|
||||
r->r_copy = 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef NEED_SWAP
|
||||
|
||||
/*
|
||||
* Byte swap routines for cross-linking.
|
||||
*/
|
||||
|
||||
void
|
||||
md_swapin_exec_hdr(h)
|
||||
struct exec *h;
|
||||
{
|
||||
int skip = 0;
|
||||
|
||||
if (!N_BADMAG(*h))
|
||||
skip = 1;
|
||||
|
||||
swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
|
||||
}
|
||||
|
||||
void
|
||||
md_swapout_exec_hdr(h)
|
||||
struct exec *h;
|
||||
{
|
||||
/* NetBSD: Always leave magic alone */
|
||||
int skip = 1;
|
||||
#if 0
|
||||
if (N_GETMAGIC(*h) == OMAGIC)
|
||||
skip = 0;
|
||||
#endif
|
||||
|
||||
swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
md_swapin_reloc(r, n)
|
||||
struct relocation_info *r;
|
||||
int n;
|
||||
{
|
||||
int bits;
|
||||
|
||||
for (; n; n--, r++) {
|
||||
r->r_address = md_swap_long(r->r_address);
|
||||
bits = ((int *)r)[1];
|
||||
r->r_symbolnum = md_swap_long(bits & 0xffffff00);
|
||||
r->r_pcrel = (bits & 1);
|
||||
r->r_length = ((bits >> 1) & 3);
|
||||
r->r_extern = ((bits >> 3) & 1);
|
||||
r->r_baserel = ((bits >> 4) & 1);
|
||||
r->r_jmptable = ((bits >> 5) & 1);
|
||||
r->r_relative = ((bits >> 6) & 1);
|
||||
#ifdef N_SIZE
|
||||
r->r_copy = ((bits >> 7) & 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
md_swapout_reloc(r, n)
|
||||
struct relocation_info *r;
|
||||
int n;
|
||||
{
|
||||
int bits;
|
||||
|
||||
for (; n; n--, r++) {
|
||||
r->r_address = md_swap_long(r->r_address);
|
||||
bits = (md_swap_long(r->r_symbolnum) & 0xffffff00);
|
||||
bits |= (r->r_pcrel & 1);
|
||||
bits |= ((r->r_length << 1) & 6);
|
||||
bits |= ((r->r_extern << 3) & 8);
|
||||
bits |= ((r->r_baserel << 4) & 0x10);
|
||||
bits |= ((r->r_jmptable << 5) & 0x20);
|
||||
bits |= ((r->r_relative << 6) & 0x40);
|
||||
#ifdef N_SIZE
|
||||
bits |= ((r->r_copy << 7) & 0x80);
|
||||
#endif
|
||||
((int *)r)[1] = bits;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
md_swapout_jmpslot(j, n)
|
||||
jmpslot_t *j;
|
||||
int n;
|
||||
{
|
||||
for (; n; n--, j++) {
|
||||
j->opcode = md_swap_short(j->opcode);
|
||||
j->addr[0] = md_swap_short(j->addr[0]);
|
||||
j->addr[1] = md_swap_short(j->addr[1]);
|
||||
j->reloc_index = md_swap_short(j->reloc_index);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NEED_SWAP */
|
198
libexec/rtld-aout/i386/md.h
Normal file
198
libexec/rtld-aout/i386/md.h
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* $Id: md.h,v 1.3 1993/10/24 00:52:40 pk Exp $ - I386 dependent definitions
|
||||
*/
|
||||
|
||||
|
||||
#if defined(CROSS_LINKER) && defined(XHOST) && XHOST==sparc
|
||||
|
||||
#define NEED_SWAP
|
||||
|
||||
#endif
|
||||
|
||||
#define MAX_ALIGNMENT (sizeof (long))
|
||||
|
||||
#ifdef NetBSD
|
||||
#define PAGSIZ __LDPGSZ
|
||||
#else
|
||||
#define PAGSIZ 4096
|
||||
#endif
|
||||
|
||||
#define N_SET_FLAG(ex,f) N_SETMAGIC(ex,N_GETMAGIC(ex), MID_MACHINE, \
|
||||
N_GETFLAG(ex)|(f))
|
||||
|
||||
#define N_IS_DYNAMIC(ex) ((N_GETFLAG(ex) & EX_DYNAMIC))
|
||||
|
||||
/*
|
||||
* Should be handled by a.out.h ?
|
||||
*/
|
||||
#define N_ADJUST(ex) (((ex).a_entry < PAGSIZ) ? -PAGSIZ : 0)
|
||||
#define TEXT_START(ex) (N_TXTADDR(ex) + N_ADJUST(ex))
|
||||
#define DATA_START(ex) (N_DATADDR(ex) + N_ADJUST(ex))
|
||||
|
||||
#define RELOC_STATICS_THROUGH_GOT_P(r) (0)
|
||||
#define JMPSLOT_NEEDS_RELOC (0)
|
||||
|
||||
#define md_got_reloc(r) (0)
|
||||
|
||||
#define md_get_rt_segment_addend(r,a) md_get_addend(r,a)
|
||||
|
||||
/* Width of a Global Offset Table entry */
|
||||
#define GOT_ENTRY_SIZE 4
|
||||
typedef long got_t;
|
||||
|
||||
typedef struct jmpslot {
|
||||
u_short opcode;
|
||||
u_short addr[2];
|
||||
u_short reloc_index;
|
||||
#define JMPSLOT_RELOC_MASK 0xffff
|
||||
} jmpslot_t;
|
||||
|
||||
#define NOP 0x90
|
||||
#define CALL 0xe890 /* NOP + CALL opcode */
|
||||
#define JUMP 0xe990 /* NOP + JMP opcode */
|
||||
#define TRAP 0xcc /* INT 3 */
|
||||
|
||||
/*
|
||||
* Byte swap defs for cross linking
|
||||
*/
|
||||
|
||||
#if !defined(NEED_SWAP)
|
||||
|
||||
#define md_swapin_exec_hdr(h)
|
||||
#define md_swapout_exec_hdr(h)
|
||||
#define md_swapin_symbols(s,n)
|
||||
#define md_swapout_symbols(s,n)
|
||||
#define md_swapin_zsymbols(s,n)
|
||||
#define md_swapout_zsymbols(s,n)
|
||||
#define md_swapin_reloc(r,n)
|
||||
#define md_swapout_reloc(r,n)
|
||||
#define md_swapin_link_dynamic(l)
|
||||
#define md_swapout_link_dynamic(l)
|
||||
#define md_swapin_link_dynamic_2(l)
|
||||
#define md_swapout_link_dynamic_2(l)
|
||||
#define md_swapin_ld_debug(d)
|
||||
#define md_swapout_ld_debug(d)
|
||||
#define md_swapin_rrs_hash(f,n)
|
||||
#define md_swapout_rrs_hash(f,n)
|
||||
#define md_swapin_link_object(l,n)
|
||||
#define md_swapout_link_object(l,n)
|
||||
#define md_swapout_jmpslot(j,n)
|
||||
#define md_swapout_got(g,n)
|
||||
#define md_swapin_ranlib_hdr(h,n)
|
||||
#define md_swapout_ranlib_hdr(h,n)
|
||||
|
||||
#endif /* NEED_SWAP */
|
||||
|
||||
#ifdef CROSS_LINKER
|
||||
|
||||
#ifdef NEED_SWAP
|
||||
|
||||
/* Define IO byte swapping routines */
|
||||
|
||||
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));
|
||||
|
||||
#define md_swapin_symbols(s,n) swap_symbols(s,n)
|
||||
#define md_swapout_symbols(s,n) swap_symbols(s,n)
|
||||
#define md_swapin_zsymbols(s,n) swap_zsymbols(s,n)
|
||||
#define md_swapout_zsymbols(s,n) swap_zsymbols(s,n)
|
||||
#define md_swapin_link_dynamic(l) swap_link_dynamic(l)
|
||||
#define md_swapout_link_dynamic(l) swap_link_dynamic(l)
|
||||
#define md_swapin_link_dynamic_2(l) swap_link_dynamic_2(l)
|
||||
#define md_swapout_link_dynamic_2(l) swap_link_dynamic_2(l)
|
||||
#define md_swapin_ld_debug(d) swap_ld_debug(d)
|
||||
#define md_swapout_ld_debug(d) swap_ld_debug(d)
|
||||
#define md_swapin_rrs_hash(f,n) swap_rrs_hash(f,n)
|
||||
#define md_swapout_rrs_hash(f,n) swap_rrs_hash(f,n)
|
||||
#define md_swapin_link_object(l,n) swapin_link_object(l,n)
|
||||
#define md_swapout_link_object(l,n) swapout_link_object(l,n)
|
||||
#define md_swapout_got(g,n) swap_longs((long*)(g),n)
|
||||
#define md_swapin_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
|
||||
#define md_swapout_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
|
||||
|
||||
#define md_swap_short(x) ( (((x) >> 8) & 0xff) | (((x) & 0xff) << 8) )
|
||||
|
||||
#define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \
|
||||
(((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000))
|
||||
|
||||
#define get_byte(p) ( ((unsigned char *)(p))[0] )
|
||||
|
||||
#define get_short(p) ( ( ((unsigned char *)(p))[1] << 8) | \
|
||||
( ((unsigned char *)(p))[0] ) \
|
||||
)
|
||||
#define get_long(p) ( ( ((unsigned char *)(p))[3] << 24) | \
|
||||
( ((unsigned char *)(p))[2] << 16) | \
|
||||
( ((unsigned char *)(p))[1] << 8 ) | \
|
||||
( ((unsigned char *)(p))[0] ) \
|
||||
)
|
||||
|
||||
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
|
||||
|
||||
#define put_short(p, v) { ((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#define put_long(p, v) { ((unsigned char *)(p))[3] = \
|
||||
((((unsigned long)(v)) >> 24) & 0xff); \
|
||||
((unsigned char *)(p))[2] = \
|
||||
((((unsigned long)(v)) >> 16) & 0xff); \
|
||||
((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#else /* We need not swap, but must pay attention to alignment: */
|
||||
|
||||
#define md_swap_short(x) (x)
|
||||
#define md_swap_long(x) (x)
|
||||
|
||||
#define get_byte(p) ( ((unsigned char *)(p))[0] )
|
||||
|
||||
#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \
|
||||
( ((unsigned char *)(p))[1] ) \
|
||||
)
|
||||
|
||||
#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \
|
||||
( ((unsigned char *)(p))[1] << 16) | \
|
||||
( ((unsigned char *)(p))[2] << 8 ) | \
|
||||
( ((unsigned char *)(p))[3] ) \
|
||||
)
|
||||
|
||||
|
||||
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
|
||||
|
||||
#define put_short(p, v) { ((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#define put_long(p, v) { ((unsigned char *)(p))[0] = \
|
||||
((((unsigned long)(v)) >> 24) & 0xff); \
|
||||
((unsigned char *)(p))[1] = \
|
||||
((((unsigned long)(v)) >> 16) & 0xff); \
|
||||
((unsigned char *)(p))[2] = \
|
||||
((((unsigned long)(v)) >> 8) & 0xff); \
|
||||
((unsigned char *)(p))[3] = \
|
||||
((((unsigned long)(v)) ) & 0xff); }
|
||||
|
||||
#endif /* NEED_SWAP */
|
||||
|
||||
#else /* Not a cross linker: use native */
|
||||
|
||||
#define md_swap_short(x) (x)
|
||||
#define md_swap_long(x) (x)
|
||||
|
||||
#define get_byte(where) (*(char *)(where))
|
||||
#define get_short(where) (*(short *)(where))
|
||||
#define get_long(where) (*(long *)(where))
|
||||
|
||||
#define put_byte(where,what) (*(char *)(where) = (what))
|
||||
#define put_short(where,what) (*(short *)(where) = (what))
|
||||
#define put_long(where,what) (*(long *)(where) = (what))
|
||||
|
||||
#endif /* CROSS_LINKER */
|
||||
|
124
libexec/rtld-aout/i386/mdprologue.S
Normal file
124
libexec/rtld-aout/i386/mdprologue.S
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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 withough 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: mdprologue.S,v 1.1 1993/10/16 21:53:16 pk Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* i386 run-time link editor entry points.
|
||||
*/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#define LCALL(x,y) .byte 0x9a ; .long y; .word x
|
||||
|
||||
.text
|
||||
.globl _binder, _binder_entry
|
||||
|
||||
/*
|
||||
* _rtl(int version, struct crt_ldso *crtp)
|
||||
*/
|
||||
#define FRAME 12 /* Size of stack frame */
|
||||
|
||||
|
||||
_rtl: # crt0 calls us here
|
||||
pushl %ebp # Allocate stack frame
|
||||
movl %esp, %ebp
|
||||
subl $FRAME, %esp
|
||||
pushl %ebx
|
||||
call 1f # PIC function prologue
|
||||
1:
|
||||
popl %ebx
|
||||
addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
|
||||
|
||||
movl 12(%ebp), %eax # Extract data from interface structure
|
||||
movl (%eax),%eax # base address of ld.so (first field)
|
||||
# setup arguments for rtld()
|
||||
movl (%ebx), %ecx # 1st entry in GOT is our __DYNAMIC
|
||||
addl %eax, %ecx # add load address
|
||||
pushl %ecx # 3rd arg
|
||||
pushl 12(%ebp) # 2nd arg == &crt.
|
||||
pushl 8(%ebp) # 1st arg == version
|
||||
addl _rtld@GOT(%ebx), %eax # relocate address of function
|
||||
call %eax # _rtld(version, crtp, DYNAMIC)
|
||||
addl $12,%esp # pop arguments
|
||||
|
||||
movl (-FRAME-4)(%ebp), %ebx # restore %ebx
|
||||
leave # remove stack frame,
|
||||
ret # let's rock
|
||||
|
||||
# First call to a procedure generally comes through here for
|
||||
# binding.
|
||||
|
||||
_binder_entry:
|
||||
pushl %ebp # setup a stack frame
|
||||
movl %esp, %ebp
|
||||
pusha # save all regs
|
||||
|
||||
movl $0, %eax # clear
|
||||
movl 4(%ebp), %esi # return address in PLT
|
||||
movw (%esi), %ax # get hold of relocation number
|
||||
subl $6, %esi # make it point to the jmpslot
|
||||
|
||||
pushl %eax # pushd arguments
|
||||
pushl %esi #
|
||||
call _binder@PLT # _binder(rpc, index)
|
||||
addl $8, %esp # pop arguments
|
||||
movl %eax, 4(%ebp) # return value from _binder() == actual
|
||||
# address of function
|
||||
popa # restore regs
|
||||
leave # remove our stack frame
|
||||
ret
|
||||
|
||||
# Special system call stubs which return real and effective user and group
|
||||
# id's. Saves overhead of making separate calls for each.
|
||||
# !! Relies on compatability option in BSD 4.three-and-a-half
|
||||
|
||||
.globl _getreuid, _getregid
|
||||
_getreuid:
|
||||
lea SYS_getuid, %eax
|
||||
LCALL(7,0)
|
||||
jc out
|
||||
movl 4(%esp), %ecx # get 1st arg
|
||||
movl %eax, (%ecx) # put value in it
|
||||
movl 8(%esp), %ecx # same for 2nd arg
|
||||
movl %edx, (%ecx) #
|
||||
ret # done
|
||||
|
||||
_getregid:
|
||||
lea SYS_getgid, %eax
|
||||
LCALL(7,0)
|
||||
jc out
|
||||
movl 4(%esp), %ecx # get 1st arg
|
||||
movl %eax, (%ecx) # put value in it
|
||||
movl 8(%esp), %ecx # same for 2nd arg
|
||||
movl %edx, (%ecx) #
|
||||
ret # done
|
||||
|
||||
out: jmp cerror@PLT # Call common error routine
|
||||
|
39
libexec/rtld-aout/md-prologue.c
Normal file
39
libexec/rtld-aout/md-prologue.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* rtld entry pseudo code - turn into assembler and tweak it
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/types.h>
|
||||
#include <a.out.h>
|
||||
#include "link.h"
|
||||
#include "md.h"
|
||||
|
||||
extern long _GOT_[];
|
||||
extern void (*rtld)();
|
||||
extern void (*binder())();
|
||||
|
||||
void
|
||||
rtld_entry(version, crtp)
|
||||
int version;
|
||||
struct crt *crtp;
|
||||
{
|
||||
register struct link_dynamic *dp;
|
||||
register void (*f)();
|
||||
|
||||
/* __DYNAMIC is first entry in GOT */
|
||||
dp = (struct link_dynamic *) (_GOT_[0]+crtp->crt_ba);
|
||||
|
||||
f = (void (*)())((long)rtld + crtp->crt_ba);
|
||||
(*f)(version, crtp, dp);
|
||||
}
|
||||
|
||||
void
|
||||
binder_entry()
|
||||
{
|
||||
extern int PC;
|
||||
struct jmpslot *sp;
|
||||
void (*func)();
|
||||
|
||||
func = binder(PC, sp->reloc_index & 0x003fffff);
|
||||
(*func)();
|
||||
}
|
1026
libexec/rtld-aout/rtld.c
Normal file
1026
libexec/rtld-aout/rtld.c
Normal file
File diff suppressed because it is too large
Load diff
203
libexec/rtld-aout/shlib.c
Normal file
203
libexec/rtld-aout/shlib.c
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* $Id: shlib.c,v 1.3 1993/10/23 00:34:26 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <a.out.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
/*
|
||||
* Standard directories to search for files specified by -l.
|
||||
*/
|
||||
#ifndef STANDARD_SEARCH_DIRS
|
||||
#define STANDARD_SEARCH_DIRS "/usr/lib", "/usr/local/lib"
|
||||
#endif
|
||||
|
||||
char *standard_search_dirs[] = {
|
||||
STANDARD_SEARCH_DIRS
|
||||
};
|
||||
|
||||
int n_search_dirs;
|
||||
|
||||
void
|
||||
add_search_dir(name)
|
||||
char *name;
|
||||
{
|
||||
n_search_dirs++;
|
||||
search_dirs = (char **)xrealloc(search_dirs,
|
||||
n_search_dirs * sizeof(char *));
|
||||
search_dirs[n_search_dirs - 1] = strdup(name);
|
||||
}
|
||||
|
||||
void
|
||||
std_search_dirs(paths)
|
||||
char *paths;
|
||||
{
|
||||
char *cp;
|
||||
int i, n;
|
||||
|
||||
if (paths != NULL)
|
||||
/* Add search directories from `paths' */
|
||||
while ((cp = strtok(paths, ":")) != NULL) {
|
||||
paths = NULL;
|
||||
add_search_dir(cp);
|
||||
}
|
||||
|
||||
/* 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++;
|
||||
if (!isdigit(*cp))
|
||||
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;
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
char *name;
|
||||
int *majorp, *minorp;
|
||||
{
|
||||
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;
|
||||
|
||||
if (dd == NULL)
|
||||
continue;
|
||||
|
||||
while ((dp = readdir(dd)) != NULL) {
|
||||
int n, j, might_take_it = 0;
|
||||
|
||||
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 && 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);
|
||||
bcopy(tmp, dewey, sizeof(dewey));
|
||||
ndewey = n;
|
||||
*majorp = dewey[0];
|
||||
*minorp = dewey[1];
|
||||
}
|
||||
closedir(dd);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
13
sbin/ldconfig/Makefile
Normal file
13
sbin/ldconfig/Makefile
Normal file
|
@ -0,0 +1,13 @@
|
|||
# $Id: Makefile,v 1.2 1993/11/03 05:20:49 cgd Exp $
|
||||
|
||||
PROG= ldconfig
|
||||
SRCS= ldconfig.c shlib.c etc.c
|
||||
LDDIR?= $(.CURDIR)/..
|
||||
LDFLAGS += -static
|
||||
CFLAGS += -I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) -O
|
||||
BINDIR= ${DESTDIR}/sbin
|
||||
MAN8 = ldconfig.0
|
||||
|
||||
.PATH: $(LDDIR) $(LDDIR)/$(MACHINE)
|
||||
|
||||
.include <bsd.prog.mk>
|
98
sbin/ldconfig/ldconfig.8
Normal file
98
sbin/ldconfig/ldconfig.8
Normal file
|
@ -0,0 +1,98 @@
|
|||
.Dd October 3, 1993
|
||||
.Dt LDCONFIG 8
|
||||
.Os NetBSD 0.9
|
||||
.Sh NAME
|
||||
.Nm ldconfig
|
||||
.Nd configure the shared library cache
|
||||
.Sh SYNOPSIS
|
||||
.Nm ldconfig
|
||||
.Op Fl rsv
|
||||
.Op Ar directory Ar ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is used to prepare a set of
|
||||
.Dq hints
|
||||
for use by the run-time linker
|
||||
.Xr ld.so
|
||||
to facilitate quick lookup of shared libraries available in multiple
|
||||
directories. It scans a set of built-in system directories and any
|
||||
.Ar directories
|
||||
specified on the command line (in the given order) looking for shared
|
||||
libraries and stores the results in the file
|
||||
.Xr /var/run/ld.so.hints
|
||||
to forstall the overhead that would otherwise result from the
|
||||
directory search operations
|
||||
.Xr ld.so
|
||||
would have to perform to load the required shared libraries.
|
||||
.Pp
|
||||
The shared libraries so found will be automatically available for loading
|
||||
if needed by the program being prepared for execution. This obviates the need
|
||||
for storing search paths within the executable.
|
||||
.Pp
|
||||
The
|
||||
.Ev LD_LIBRARY_PATH
|
||||
environment variable can be used to override the use of
|
||||
directories (or the order thereof) from the cache or to specify additional
|
||||
directories where shared libraries might be found.
|
||||
.Ev LD_LIBRARY_PATH
|
||||
is a
|
||||
.Sq \:
|
||||
separated list of directory paths which are searched by
|
||||
.Xr ld.so
|
||||
when it needs to load a shared library. It can be viewed as the run-time
|
||||
equivalent of the
|
||||
.Fl L
|
||||
switch of
|
||||
.Xr ld.
|
||||
.Pp
|
||||
.Nm Ldconfig
|
||||
is typically run as part of the boot sequence.
|
||||
.Pp
|
||||
The following options recognized by
|
||||
.Nm ldconfig:
|
||||
.Bl -tag -width indent
|
||||
.It Fl r
|
||||
Lists the current contents of
|
||||
.Xr ld.so.hints
|
||||
on the standard output. The hints file will not be modified.
|
||||
.It Fl s
|
||||
Do not scan
|
||||
.Nm ldconfig
|
||||
's builtin system directories
|
||||
.Sq /usr/lib
|
||||
and
|
||||
.Sq /usr/local/lib
|
||||
for shared libraries.
|
||||
.It Fl v
|
||||
Switch on verbose mode.
|
||||
.Sh Security
|
||||
Special care must be taken when loading shared libraries into the address
|
||||
space of
|
||||
.Ev set-user-Id
|
||||
programs. Whenever such a program is run,
|
||||
.Xr ld.so
|
||||
will only load shared libraries from the
|
||||
.Ev ld.so.hints
|
||||
file. In particular, the
|
||||
.Ev LD_LIBRARY_PATH
|
||||
is not used to search for libraries. Thus, the role of ldconfig is dual. In
|
||||
addition to building a set of hints for quick lookup, it also serves to
|
||||
specify the trusted collection of directories from which shared objects can
|
||||
be safely loaded. It is presumed that the set of directories specified to
|
||||
.Nm ldconfig
|
||||
are under control of the system's administrator.
|
||||
.Xr ld.so
|
||||
further assists set-user-Id programs by erasing the
|
||||
.Ev LD_LIBRARY_PATH
|
||||
from the environment.
|
||||
|
||||
.Sh FILES
|
||||
.Xr /var/run/ld.so.hints
|
||||
.Sh SEE ALSO
|
||||
.Xr ld 1 ,
|
||||
.Xr link 5
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility first appeared in SunOS 4.0, it appeared in its current form
|
||||
in NetBSD 0.9a.
|
411
sbin/ldconfig/ldconfig.c
Normal file
411
sbin/ldconfig/ldconfig.c
Normal file
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* 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 withough 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: ldconfig.c,v 1.1 1993/10/23 00:17:03 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ar.h>
|
||||
#include <ranlib.h>
|
||||
#include <a.out.h>
|
||||
#include <stab.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
#undef major
|
||||
#undef minor
|
||||
|
||||
char *progname;
|
||||
static int verbose;
|
||||
static int nostd;
|
||||
static int justread;
|
||||
|
||||
#define MAXDEWEY 8
|
||||
struct shlib_list {
|
||||
/* Internal list of shared libraries found */
|
||||
char *name;
|
||||
char *path;
|
||||
int dewey[MAXDEWEY];
|
||||
int ndewey;
|
||||
#define major dewey[0]
|
||||
#define minor dewey[1]
|
||||
struct shlib_list *next;
|
||||
};
|
||||
|
||||
static struct shlib_list *shlib_head = NULL, **shlib_tail = &shlib_head;
|
||||
|
||||
static void enter __P((char *, char *, char *, int *, int));
|
||||
static int dodir __P((char *));
|
||||
static int build_hints __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i, c;
|
||||
int rval = 0;
|
||||
extern int optind;
|
||||
|
||||
if ((progname = strrchr(argv[0], '/')) == NULL)
|
||||
progname = argv[0];
|
||||
else
|
||||
progname++;
|
||||
|
||||
while ((c = getopt(argc, argv, "rsv")) != EOF) {
|
||||
switch (c) {
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 's':
|
||||
nostd = 1;
|
||||
break;
|
||||
case 'r':
|
||||
justread = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Usage: %s [-v] [dir ...]\n", progname);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (justread)
|
||||
return listhints();
|
||||
|
||||
if (!nostd)
|
||||
std_search_dirs(NULL);
|
||||
|
||||
for (i = 0; i < n_search_dirs; i++)
|
||||
rval |= dodir(search_dirs[i]);
|
||||
|
||||
for (i = optind; i < argc; i++)
|
||||
rval |= dodir(argv[i]);
|
||||
|
||||
rval |= build_hints();
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
dodir(dir)
|
||||
char *dir;
|
||||
{
|
||||
DIR *dd;
|
||||
struct dirent *dp;
|
||||
char name[MAXPATHLEN], rest[MAXPATHLEN];
|
||||
int dewey[MAXDEWEY], ndewey;
|
||||
|
||||
if ((dd = opendir(dir)) == NULL) {
|
||||
perror(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dd)) != NULL) {
|
||||
int n;
|
||||
|
||||
name[0] = rest[0] = '\0';
|
||||
|
||||
n = sscanf(dp->d_name, "lib%[^.].so.%s",
|
||||
name, rest);
|
||||
|
||||
if (n < 2 || rest[0] == '\0')
|
||||
continue;
|
||||
|
||||
ndewey = getdewey(dewey, rest);
|
||||
enter(dir, dp->d_name, name, dewey, ndewey);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
enter(dir, file, name, dewey, ndewey)
|
||||
char *dir, *file, *name;
|
||||
int dewey[], ndewey;
|
||||
{
|
||||
struct shlib_list *shp;
|
||||
|
||||
for (shp = shlib_head; shp; shp = shp->next) {
|
||||
if (strcmp(name, shp->name) != 0 || major != shp->major)
|
||||
continue;
|
||||
|
||||
/* Name matches existing entry */
|
||||
if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) {
|
||||
|
||||
/* Update this entry with higher versioned lib */
|
||||
if (verbose)
|
||||
printf("Updating lib%s.%d.%d to %s/%s\n",
|
||||
shp->name, shp->major, shp->minor,
|
||||
dir, file);
|
||||
|
||||
free(shp->name);
|
||||
shp->name = strdup(name);
|
||||
free(shp->path);
|
||||
shp->path = concat(dir, "/", file);
|
||||
bcopy(dewey, shp->dewey, sizeof(shp->dewey));
|
||||
shp->ndewey = ndewey;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (shp)
|
||||
/* Name exists: older version or just updated */
|
||||
return;
|
||||
|
||||
/* Allocate new list element */
|
||||
if (verbose)
|
||||
printf("Adding %s/%s\n", dir, file);
|
||||
|
||||
shp = (struct shlib_list *)xmalloc(sizeof *shp);
|
||||
shp->name = strdup(name);
|
||||
shp->path = concat(dir, "/", file);
|
||||
bcopy(dewey, shp->dewey, MAXDEWEY);
|
||||
shp->ndewey = ndewey;
|
||||
shp->next = NULL;
|
||||
|
||||
*shlib_tail = shp;
|
||||
shlib_tail = &shp->next;
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG
|
||||
/* test */
|
||||
#undef _PATH_LD_HINTS
|
||||
#define _PATH_LD_HINTS "./ld.so.hints"
|
||||
#endif
|
||||
|
||||
int
|
||||
hinthash(cp, vmajor, vminor)
|
||||
char *cp;
|
||||
int vmajor, vminor;
|
||||
{
|
||||
int k = 0;
|
||||
|
||||
while (*cp)
|
||||
k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
|
||||
|
||||
k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
|
||||
k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
int
|
||||
build_hints()
|
||||
{
|
||||
struct hints_header hdr;
|
||||
struct hints_bucket *blist;
|
||||
struct shlib_list *shp;
|
||||
char *strtab;
|
||||
int i, n, str_index = 0;
|
||||
int strtab_sz = 0; /* Total length of strings */
|
||||
int nhints = 0; /* Total number of hints */
|
||||
int fd;
|
||||
char *tmpfile;
|
||||
|
||||
for (shp = shlib_head; shp; shp = shp->next) {
|
||||
strtab_sz += 1 + strlen(shp->name);
|
||||
strtab_sz += 1 + strlen(shp->path);
|
||||
nhints++;
|
||||
}
|
||||
|
||||
/* Fill hints file header */
|
||||
hdr.hh_magic = HH_MAGIC;
|
||||
hdr.hh_version = LD_HINTS_VERSION_1;
|
||||
hdr.hh_nbucket = 1 * nhints;
|
||||
n = hdr.hh_nbucket * sizeof(struct hints_bucket);
|
||||
hdr.hh_hashtab = sizeof(struct hints_header);
|
||||
hdr.hh_strtab = hdr.hh_hashtab + n;
|
||||
hdr.hh_strtab_sz = strtab_sz;
|
||||
hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz;
|
||||
|
||||
if (verbose)
|
||||
printf("Totals: entries %d, buckets %d, string size %d\n",
|
||||
nhints, hdr.hh_nbucket, strtab_sz);
|
||||
|
||||
/* Allocate buckets and string table */
|
||||
blist = (struct hints_bucket *)xmalloc(n);
|
||||
bzero((char *)blist, n);
|
||||
for (i = 0; i < hdr.hh_nbucket; i++)
|
||||
/* Empty all buckets */
|
||||
blist[i].hi_next = -1;
|
||||
|
||||
strtab = (char *)xmalloc(strtab_sz);
|
||||
|
||||
/* Enter all */
|
||||
for (shp = shlib_head; shp; shp = shp->next) {
|
||||
struct hints_bucket *bp;
|
||||
|
||||
bp = blist +
|
||||
(hinthash(shp->name, shp->major, shp->minor) % hdr.hh_nbucket);
|
||||
|
||||
if (bp->hi_pathx) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < hdr.hh_nbucket; i++) {
|
||||
if (blist[i].hi_pathx == 0)
|
||||
break;
|
||||
}
|
||||
if (i == hdr.hh_nbucket) {
|
||||
fprintf(stderr, "Bummer!\n");
|
||||
return -1;
|
||||
}
|
||||
while (bp->hi_next != -1)
|
||||
bp = &blist[bp->hi_next];
|
||||
bp->hi_next = i;
|
||||
bp = blist + i;
|
||||
}
|
||||
|
||||
/* Insert strings in string table */
|
||||
bp->hi_namex = str_index;
|
||||
strcpy(strtab + str_index, shp->name);
|
||||
str_index += 1 + strlen(shp->name);
|
||||
|
||||
bp->hi_pathx = str_index;
|
||||
strcpy(strtab + str_index, shp->path);
|
||||
str_index += 1 + strlen(shp->path);
|
||||
|
||||
/* Copy versions */
|
||||
bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey));
|
||||
bp->hi_ndewey = shp->ndewey;
|
||||
}
|
||||
|
||||
tmpfile = concat(_PATH_LD_HINTS, "+", "");
|
||||
if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, 0444)) == -1) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mywrite(&hdr, 1, sizeof(struct hints_header), fd);
|
||||
mywrite(blist, hdr.hh_nbucket, sizeof(struct hints_bucket), fd);
|
||||
mywrite(strtab, strtab_sz, 1, fd);
|
||||
|
||||
if (close(fd) != 0) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now, install real file */
|
||||
if (unlink(_PATH_LD_HINTS) != 0 && errno != ENOENT) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rename(tmpfile, _PATH_LD_HINTS) != 0) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
listhints()
|
||||
{
|
||||
int fd;
|
||||
caddr_t addr;
|
||||
long msize;
|
||||
struct hints_header *hdr;
|
||||
struct hints_bucket *blist;
|
||||
char *strtab;
|
||||
int i;
|
||||
|
||||
if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msize = PAGSIZ;
|
||||
addr = mmap(0, msize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
|
||||
|
||||
if (addr == (caddr_t)-1) {
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr = (struct hints_header *)addr;
|
||||
if (HH_BADMAG(*hdr)) {
|
||||
fprintf(stderr, "%s: Bad magic: %d\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->hh_version != LD_HINTS_VERSION_1) {
|
||||
fprintf(stderr, "Unsupported version: %d\n", hdr->hh_version);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->hh_ehints > msize) {
|
||||
if (mmap(addr+msize, hdr->hh_ehints - msize,
|
||||
PROT_READ, MAP_FILE|MAP_COPY|MAP_FIXED,
|
||||
fd, msize) != (caddr_t)(addr+msize)) {
|
||||
|
||||
perror(_PATH_LD_HINTS);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
blist = (struct hints_bucket *)(addr + hdr->hh_hashtab);
|
||||
strtab = (char *)(addr + hdr->hh_strtab);
|
||||
|
||||
printf("%s:\n", _PATH_LD_HINTS);
|
||||
for (i = 0; i < hdr->hh_nbucket; i++) {
|
||||
struct hints_bucket *bp = &blist[i];
|
||||
|
||||
/* Sanity check */
|
||||
if (bp->hi_namex >= hdr->hh_strtab_sz) {
|
||||
fprintf(stderr, "Bad name index: %#x\n", bp->hi_namex);
|
||||
return -1;
|
||||
}
|
||||
if (bp->hi_pathx >= hdr->hh_strtab_sz) {
|
||||
fprintf(stderr, "Bad path index: %#x\n", bp->hi_pathx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("\t-l%s.%d.%d => %s\n",
|
||||
strtab + bp->hi_namex, bp->hi_major, bp->hi_minor,
|
||||
strtab + bp->hi_pathx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
7
usr.bin/ldd/Makefile
Normal file
7
usr.bin/ldd/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
# $Id: Makefile,v 1.2 1993/10/22 21:10:42 pk Exp $
|
||||
|
||||
PROG= ldd
|
||||
SRCS= ldd.c
|
||||
BINDIR= ${DESTDIR}/usr/bin
|
||||
|
||||
.include <bsd.prog.mk>
|
25
usr.bin/ldd/ldd.1
Normal file
25
usr.bin/ldd/ldd.1
Normal file
|
@ -0,0 +1,25 @@
|
|||
.Dd October 22, 1993
|
||||
.Dt LDD 1
|
||||
.Os NetBSD 0.9
|
||||
.Sh NAME
|
||||
.Nm ldd
|
||||
.Nd list dynamic object dependencies
|
||||
.Sh SYNOPSIS
|
||||
.Nm ldd
|
||||
.Op Ar filename Ar ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm ldd
|
||||
displays all shared objects that are needed to run the given program.
|
||||
Contrary to nm(1), the list includes
|
||||
.Dq indirect
|
||||
depedencies that are the result of needed shared objects which themselves
|
||||
depend on yet other shared objects.
|
||||
.Sh SEE ALSO
|
||||
.Xr ld 1 ,
|
||||
.Xr ld.so 1 ,
|
||||
.Xr nm 1
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm ldd
|
||||
utility first appeared in SunOS 4.0, it appeared in its current form
|
||||
in NetBSD 0.9a.
|
139
usr.bin/ldd/ldd.c
Normal file
139
usr.bin/ldd/ldd.c
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* 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 withough 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: ldd.c,v 1.3 1993/10/31 14:54:29 pk Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <a.out.h>
|
||||
|
||||
static char *progname;
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s <filename> ...\n", progname);
|
||||
}
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int rval = 0;
|
||||
int c;
|
||||
extern int optind;
|
||||
|
||||
if ((progname = strrchr(argv[0], '/')) == NULL)
|
||||
progname = argv[0];
|
||||
else
|
||||
progname++;
|
||||
|
||||
while ((c = getopt(argc, argv, "")) != EOF) {
|
||||
switch (c) {
|
||||
default:
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc <= 0) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* ld.so magic */
|
||||
setenv("LD_TRACE_LOADED_OBJECTS", "", 1);
|
||||
|
||||
while (argc--) {
|
||||
int fd;
|
||||
struct exec hdr;
|
||||
int status;
|
||||
|
||||
if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
|
||||
perror(*argv);
|
||||
rval |= 1;
|
||||
argv++;
|
||||
continue;
|
||||
}
|
||||
if (read(fd, &hdr, sizeof hdr) != sizeof hdr ||
|
||||
!(N_GETFLAG(hdr) & EX_DYNAMIC)) {
|
||||
fprintf(stderr, "%s: not a dynamic executable\n",
|
||||
*argv);
|
||||
(void)close(fd);
|
||||
rval |= 1;
|
||||
argv++;
|
||||
continue;
|
||||
}
|
||||
(void)close(fd);
|
||||
|
||||
printf("%s:\n", *argv);
|
||||
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
perror("fork");
|
||||
exit(1);
|
||||
break;
|
||||
default:
|
||||
if (wait(&status) <= 0)
|
||||
perror("wait");
|
||||
|
||||
if (WIFSIGNALED(status)) {
|
||||
fprintf(stderr, "%s: signal %d\n",
|
||||
*argv, WTERMSIG(status));
|
||||
rval |= 1;
|
||||
} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
|
||||
fprintf(stderr, "%s: exit status %d\n",
|
||||
*argv, WEXITSTATUS(status));
|
||||
rval |= 1;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
rval != execl(*argv, *argv, NULL) != 0;
|
||||
perror(*argv);
|
||||
_exit(1);
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
Loading…
Reference in a new issue