* Copyright (c) 1993 Paul Kranenburg
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Paul Kranenburg.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* $Id: rtld.c,v 1.14 1994/01/14 11:47:00 jkh Exp $
#include <machine/vmparam.h>
#include <sys/resource.h>
#define MAP_COPY MAP_PRIVATE
#ifndef BSD /* Need do better than this */
* Loader private data, hung off <so_map>->som_spd
struct so_map
*spd_parent
;
long spd_offset
; /* Correction for Sun main programs */
#define LM_PRIVATE(smp) ((struct somap_private *)(smp)->som_spd)
#define LM_OFFSET(smp) (LM_PRIVATE(smp)->spd_offset)
#define LM_OFFSET(smp) (0)
/* Base address for section_dispatch_table entries */
#define LM_LDBASE(smp) (smp->som_addr + LM_OFFSET(smp))
/* Start of text segment */
#define LM_TXTADDR(smp) (smp->som_addr == (caddr_t)0 ? PAGSIZ : 0)
/* Start of run-time relocation_info */
#define LM_REL(smp) ((struct relocation_info *) \
(smp->som_addr + LM_OFFSET(smp) + LD_REL((smp)->som_dynamic)))
#define LM_SYMBOL(smp, i) ((struct nzlist *) \
(smp->som_addr + LM_OFFSET(smp) + LD_SYMBOL((smp)->som_dynamic) + \
i * (LD_VERSION_NZLIST_P(smp->som_dynamic->d_version) ? \
sizeof(struct nzlist) : sizeof(struct nlist))))
/* Start of hash table */
#define LM_HASH(smp) ((struct rrs_hash *) \
((smp)->som_addr + LM_OFFSET(smp) + LD_HASH((smp)->som_dynamic)))
#define LM_STRINGS(smp) ((char *) \
((smp)->som_addr + LM_OFFSET(smp) + LD_STRINGS((smp)->som_dynamic)))
#define LM_ETEXT(smp) ((char *) \
((smp)->som_addr + LM_TXTADDR(smp) + LD_TEXTSZ((smp)->som_dynamic)))
/* PLT is in data segment, so don't use LM_OFFSET here */
#define LM_PLT(smp) ((jmpslot_t *) \
((smp)->som_addr + LD_PLT((smp)->som_dynamic)))
#define LM_PARENT(smp) (LM_PRIVATE(smp)->spd_parent)
static char *main_progname
= "main";
struct so_map
*link_map_head
, *main_map
;
struct so_map
**link_map_tail
= &link_map_head
;
struct rt_symbol
*rt_symbol_head
;
static void *dlopen
__P((char *, int));
static int dlclose
__P((void *));
static void *dlsym
__P((void *, char *));
static int dlctl
__P((void *, int, void *));
static struct ld_entry ld_entry
= {
dlopen
, dlclose
, dlsym
, dlctl
void xprintf
__P((char *, ...));
static void init_brk
__P((void));
static void load_objects
__P(( struct crt_ldso
*,
static struct so_map
*map_object
__P((struct sod
*, struct so_map
*));
static struct so_map
*alloc_link_map
__P(( char *, struct sod
*,
struct so_map
*, caddr_t
,
static void inline check_text_reloc
__P(( struct relocation_info
*,
static void reloc_map
__P((struct so_map
*));
static void reloc_copy
__P((struct so_map
*));
static void init_map
__P((struct so_map
*, char *));
static char *rtfindlib
__P((char *, int, int, int *));
void binder_entry
__P((void));
long binder
__P((jmpslot_t
*));
static struct nzlist
*lookup
__P((char *, struct so_map
**, int));
static inline struct rt_symbol
*lookup_rts
__P((char *));
static struct rt_symbol
*enter_rts
__P((char *, long, int, caddr_t
,
strcmp (register const char *s1
, register const char *s2
)
return (*(unsigned char *)s1
- *(unsigned char *)--s2
);
#include "md-static-funcs.c"
* Called from assembler stub that has set up crtp (passed from crt0)
* and dp (our __DYNAMIC).
int nreloc
; /* # of ld.so relocations */
struct relocation_info
*reloc
;
if ( version
!= CRT_VERSION_BSD_2
&&
version
!= CRT_VERSION_BSD_3
&&
version
!= CRT_VERSION_SUN
)
/* Fixup __DYNAMIC structure */
(long)dp
->d_un
.d_sdt
+= crtp
->crt_ba
;
/* Divide by hand to avoid possible use of library division routine */
for ( nreloc
= 0, n
= LD_RELSZ(dp
);
n
-= sizeof(struct relocation_info
) ) nreloc
++;
for ( reloc
= (struct relocation_info
*)(LD_REL(dp
) + crtp
->crt_ba
);
register long addr
= reloc
->r_address
+ crtp
->crt_ba
;
md_relocate_simple(reloc
, crtp
->crt_ba
, addr
);
if (version
>= CRT_VERSION_BSD_3
)
main_progname
= crtp
->crt_prog
;
/* Setup out (private) environ variable */
/* Get user and group identifiers */
uid
= getuid(); euid
= geteuid();
gid
= getgid(); egid
= getegid();
careful
= (uid
!= euid
) || (gid
!= egid
);
unsetenv("LD_LIBRARY_PATH");
unsetenv("LD_RUN_PATH"); /* In case we ever implement this */
/* Setup directory search */
std_search_dirs(getenv("LD_LIBRARY_PATH"));
/* Load required objects into the process address space */
/* Relocate all loaded objects according to their RRS segments */
for (smp
= link_map_head
; smp
; smp
= smp
->som_next
) {
if (LM_PRIVATE(smp
)->spd_flags
& RTLD_RTLD
)
/* Copy any relocated initialized data. */
for (smp
= link_map_head
; smp
; smp
= smp
->som_next
) {
if (LM_PRIVATE(smp
)->spd_flags
& RTLD_RTLD
)
/* Call any object initialization routines. */
for (smp
= link_map_head
; smp
; smp
= smp
->som_next
) {
if (LM_PRIVATE(smp
)->spd_flags
& RTLD_RTLD
)
/* Fill in some field in main's __DYNAMIC structure */
crtp
->crt_dp
->d_entry
= &ld_entry
;
crtp
->crt_dp
->d_un
.d_sdt
->sdt_loaded
= link_map_head
->som_next
;
ddp
= crtp
->crt_dp
->d_debug
;
ddp
->dd_cc
= rt_symbol_head
;
if (ddp
->dd_in_debugger
) {
caddr_t addr
= (caddr_t
)((long)crtp
->crt_bp
& (~(PAGSIZ
- 1)));
/* Set breakpoint for the benefit of debuggers */
if (mprotect(addr
, PAGSIZ
,
PROT_READ
|PROT_WRITE
|PROT_EXEC
) == -1) {
fatal("Cannot set breakpoint (%s)\n", main_progname
);
md_set_breakpoint(crtp
->crt_bp
, &ddp
->dd_bpt_shadow
);
if (mprotect(addr
, PAGSIZ
, PROT_READ
|PROT_EXEC
) == -1) {
ddp
->dd_bpt_addr
= crtp
->crt_bp
;
/* Close our file descriptor */
(void)close(crtp
->crt_ldfd
);
int tracing
= (int)getenv("LD_TRACE_LOADED_OBJECTS");
/* Handle LD_PRELOAD's here */
/* Make an entry for the main program */
smp
= alloc_link_map(main_progname
, (struct sod
*)0, (struct so_map
*)0,
(caddr_t
)0, crtp
->crt_dp
);
LM_PRIVATE(smp
)->spd_refcount
++;
LM_PRIVATE(smp
)->spd_flags
|= RTLD_MAIN
;
/* Make an entry for ourselves */
smp
= alloc_link_map("/usr/libexec/ld.so", (struct sod
*)0, (struct so_map
*)0,
(caddr_t
)crtp
->crt_ba
, dp
);
LM_PRIVATE(smp
)->spd_refcount
++;
LM_PRIVATE(smp
)->spd_flags
|= RTLD_RTLD
;
for (smp
= link_map_head
; smp
; smp
= smp
->som_next
) {
if (LM_PRIVATE(smp
)->spd_flags
& RTLD_RTLD
)
next
= LD_NEED(smp
->som_dynamic
);
sodp
= (struct sod
*)(LM_LDBASE(smp
) + next
);
if ((newmap
= map_object(sodp
, smp
)) == NULL
) {
(sodp
->sod_name
+ LM_LDBASE(smp
));
char *fmt
= sodp
->sod_library
?
"%s: lib%s.so.%d.%d: %s\n" :
fatal(fmt
, main_progname
, name
,
newmap
= alloc_link_map(NULL
, sodp
, smp
, 0, 0);
LM_PRIVATE(newmap
)->spd_refcount
++;
for (smp
= link_map_head
; smp
; smp
= smp
->som_next
) {
if ((sodp
= smp
->som_sod
) == NULL
)
name
= sodp
->sod_name
+ LM_LDBASE(LM_PARENT(smp
));
if ((path
= smp
->som_path
) == NULL
)
printf("\t-l%s.%d => %s (%#x)\n", name
,
sodp
->sod_major
, path
, smp
->som_addr
);
printf("\t%s => %s (%#x)\n", name
, path
, smp
->som_addr
);
* Allocate a new link map for an shared object NAME loaded at ADDR as a
* result of the presence of link object LOP in the link map PARENT.
alloc_link_map(path
, sodp
, parent
, addr
, dp
)
struct somap_private
*smpp
;
smpp
= (struct somap_private
*)xmalloc(sizeof(struct somap_private
));
smp
= (struct so_map
*)xmalloc(sizeof(struct so_map
));
link_map_tail
= &smp
->som_next
;
smp
->som_spd
= (caddr_t
)smpp
;
/*XXX*/ if (addr
== 0) main_map
= smp
;
smpp
->spd_parent
= parent
;
(addr
==0 && dp
&& dp
->d_version
==LD_VERSION_SUN
) ? PAGSIZ
: 0;
* Map object identified by link object LOP which was found
char *path
, *name
= (char *)(sodp
->sod_name
+ LM_LDBASE(smp
));
path
= rtfindlib(name
, sodp
->sod_major
,
sodp
->sod_minor
, &usehints
);
if (careful
&& *name
!= '/') {
/* Check if already loaded */
for (p
= link_map_head
; p
; p
= p
->som_next
)
if (p
->som_path
&& strcmp(p
->som_path
, path
) == 0)
if ((fd
= open(path
, O_RDONLY
, 0)) == -1) {
if (read(fd
, &hdr
, sizeof(hdr
)) != sizeof(hdr
)) {
if ((addr
= mmap(0, hdr
.a_text
+ hdr
.a_data
,
MAP_FILE
|MAP_COPY
, fd
, 0)) == (caddr_t
)-1) {
if (mmap(addr
+ hdr
.a_text
, hdr
.a_data
,
PROT_READ
|PROT_WRITE
|PROT_EXEC
,
MAP_FILE
|MAP_FIXED
|MAP_COPY
,
fd
, hdr
.a_text
) == (caddr_t
)-1) {
if ((fd
= open("/dev/zero", O_RDWR
, 0)) == -1)
if (hdr
.a_bss
&& mmap(addr
+ hdr
.a_text
+ hdr
.a_data
, hdr
.a_bss
,
PROT_READ
|PROT_WRITE
|PROT_EXEC
,
MAP_ANON
|MAP_FIXED
|MAP_COPY
,
fd
, hdr
.a_text
+ hdr
.a_data
) == (caddr_t
)-1)
/* Assume _DYNAMIC is the first data item */
dp
= (struct _dynamic
*)(addr
+hdr
.a_text
);
/* Fixup __DYNAMIC structure */
(long)dp
->d_un
.d_sdt
+= (long)addr
;
return alloc_link_map(path
, sodp
, smp
, addr
, dp
);
check_text_reloc(r
, smp
, addr
)
struct relocation_info
*r
;
if (addr
>= LM_ETEXT(smp
))
LM_SYMBOL(smp
, RELOC_SYMBOL(r
))->nz_strx
;
if (getenv("LD_WARN_NON_PURE_CODE") != NULL
)
"ld.so: warning: non pure code in %s at %x (%s)\n",
smp
->som_path
, r
->r_address
, sym
);
if (smp
->som_write
== 0 &&
mprotect(smp
->som_addr
+ LM_TXTADDR(smp
),
LD_TEXTSZ(smp
->som_dynamic
),
PROT_READ
|PROT_WRITE
|PROT_EXEC
) == -1) {
fatal("Cannot enable writes to %s:%s\n",
main_progname
, smp
->som_path
);
struct _dynamic
*dp
= smp
->som_dynamic
;
struct relocation_info
*r
= LM_REL(smp
);
struct relocation_info
*rend
= r
+ LD_RELSZ(dp
)/sizeof(*r
);
long symbolbase
= (long)LM_SYMBOL(smp
, 0);
char *stringbase
= LM_STRINGS(smp
);
int symsize
= LD_VERSION_NZLIST_P(dp
->d_version
) ?
md_fix_jmpslot(LM_PLT(smp
),
(long)LM_PLT(smp
), (long)binder_entry
);
caddr_t addr
= smp
->som_addr
+ r
->r_address
;
check_text_reloc(r
, smp
, addr
);
struct so_map
*src_map
= NULL
;
long relocation
= md_get_addend(r
, addr
);
(symbolbase
+ symsize
* RELOC_SYMBOL(r
));
if (p
->nz_type
== (N_SETV
+ N_EXT
))
sym
= stringbase
+ p
->nz_strx
;
np
= lookup(sym
, &src_map
, 0/*XXX-jumpslots!*/);
fatal("Undefined symbol \"%s\" in %s:%s\n",
sym
, main_progname
, smp
->som_path
);
* Found symbol definition.
* If it's in a link map, adjust value
* according to the load address of that map.
* Otherwise it's a run-time allocated common
* whose value is already up-to-date.
relocation
+= np
->nz_value
;
relocation
+= (long)src_map
->som_addr
;
relocation
-= (long)smp
->som_addr
;
if (RELOC_COPY_P(r
) && src_map
) {
src_map
->som_addr
+ np
->nz_value
,
md_relocate(r
, relocation
, addr
, 0);
md_get_rt_segment_addend(r
, addr
)
+ (long)smp
->som_addr
, addr
, 0);
if (mprotect(smp
->som_addr
+ LM_TXTADDR(smp
),
LD_TEXTSZ(smp
->som_dynamic
),
PROT_READ
|PROT_EXEC
) == -1) {
fatal("Cannot disable writes to %s:%s\n",
main_progname
, smp
->som_path
);
for (rtsp
= rt_symbol_head
; rtsp
; rtsp
= rtsp
->rt_next
)
if ((rtsp
->rt_smp
== NULL
|| rtsp
->rt_smp
== smp
) &&
rtsp
->rt_sp
->nz_type
== N_DATA
+ N_EXT
) {
bcopy(rtsp
->rt_srcaddr
, (caddr_t
)rtsp
->rt_sp
->nz_value
,
struct so_map
*src_map
= smp
;
np
= lookup(sym
, &src_map
, 1);
(*(void (*)())(src_map
->som_addr
+ np
->nz_value
))();
* Run-time common symbol table.
static struct rt_symbol
*rt_symtab
[RTC_TABSIZE
];
* Compute hash value for run-time symbol table
k
= (((k
<< 1) + (k
>> 14)) ^ (*cp
++)) & 0x3fff;
* Lookup KEY in the run-time common symbol table.
static inline struct rt_symbol
*
register struct rt_symbol
*rtsp
;
/* Determine which bucket. */
hashval
= hash_string(key
) % RTC_TABSIZE
;
for (rtsp
= rt_symtab
[hashval
]; rtsp
; rtsp
= rtsp
->rt_link
)
if (strcmp(key
, rtsp
->rt_sp
->nz_name
) == 0)
static struct rt_symbol
*
enter_rts(name
, value
, type
, srcaddr
, size
, smp
)
register struct rt_symbol
*rtsp
, **rpp
;
/* Determine which bucket */
hashval
= hash_string(name
) % RTC_TABSIZE
;
for (rpp
= &rt_symtab
[hashval
]; *rpp
; rpp
= &(*rpp
)->rt_link
)
/* Allocate new common symbol */
rtsp
= (struct rt_symbol
*)malloc(sizeof(struct rt_symbol
));
rtsp
->rt_sp
= (struct nzlist
*)malloc(sizeof(struct nzlist
));
rtsp
->rt_sp
->nz_name
= strdup(name
);
rtsp
->rt_sp
->nz_value
= value
;
rtsp
->rt_sp
->nz_type
= type
;
rtsp
->rt_sp
->nz_size
= size
;
rtsp
->rt_srcaddr
= srcaddr
;
/* Link onto linear list as well */
rtsp
->rt_next
= rt_symbol_head
;
* Lookup NAME in the link maps. The link map producing a definition
* is returned in SRC_MAP. If SRC_MAP is not NULL on entry the search is
* confined to that map. If STRONG is set, the symbol returned must
* have a proper type (used by binder()).
lookup(name
, src_map
, strong
)
struct so_map
**src_map
; /* IN/OUT */
if ((rtsp
= lookup_rts(name
)) != NULL
)
* Search all maps for a definition of NAME
for (smp
= link_map_head
; smp
; smp
= smp
->som_next
) {
int buckets
= LD_BUCKETS(smp
->som_dynamic
);
struct rrs_hash
*hashbase
;
if (LM_PRIVATE(smp
)->spd_flags
& RTLD_RTLD
)
if (*src_map
&& smp
!= *src_map
)
* Compute bucket in which the symbol might be found.
for (cp
= name
; *cp
; cp
++)
hashval
= (hashval
<< 1) + *cp
;
hashval
= (hashval
& 0x7fffffff) % buckets
;
if (hp
->rh_symbolnum
== -1)
/* Nothing in this bucket */
symbolbase
= (long)LM_SYMBOL(smp
, 0);
stringbase
= LM_STRINGS(smp
);
symsize
= LD_VERSION_NZLIST_P(smp
->som_dynamic
->d_version
)?
(symbolbase
+ hp
->rh_symbolnum
* symsize
);
cp
= stringbase
+ np
->nz_strx
;
if (strcmp(cp
, name
) == 0)
hp
= hashbase
+ hp
->rh_next
;
/* Nothing in this bucket */
* We have a symbol with the name we're looking for.
/* It's not a definition */
if (np
->nz_type
== N_UNDF
+N_EXT
&& np
->nz_value
!= 0) {
if (np
->nz_other
== AUX_FUNC
) {
/* It's a weak function definition */
/* It's a common, note value and continue search */
if (common_size
< np
->nz_value
)
common_size
= np
->nz_value
;
* It's a common, enter into run-time common symbol table.
rtsp
= enter_rts(name
, (long)calloc(1, common_size
),
N_UNDF
+ N_EXT
, 0, common_size
, NULL
);
xprintf("Allocating common: %s size %d at %#x\n", name
, common_size
, rtsp
->rt_sp
->nz_value
);
* This routine is called from the jumptable to resolve
* procedure calls to shared objects.
struct so_map
*smp
, *src_map
= NULL
;
* Find the PLT map that contains JSP.
for (smp
= link_map_head
; smp
; smp
= smp
->som_next
) {
jsp
< LM_PLT(smp
) + LD_PLTSZ(smp
->som_dynamic
)/sizeof(*jsp
))
fatal("Call to binder from unknown location: %#x\n", jsp
);
index
= jsp
->reloc_index
& JMPSLOT_RELOC_MASK
;
/* Get the local symbol this jmpslot refers to */
LM_SYMBOL(smp
,RELOC_SYMBOL(&LM_REL(smp
)[index
]))->nz_strx
;
np
= lookup(sym
, &src_map
, 1);
fatal("Undefined symbol \"%s\" called from %s:%s at %#x",
sym
, main_progname
, smp
->som_path
, jsp
);
/* Fixup jmpslot so future calls transfer directly to target */
addr
+= (long)src_map
->som_addr
;
md_fix_jmpslot(jsp
, (long)jsp
, addr
);
xprintf(" BINDER: %s located at = %#x in %s\n", sym
, addr
, src_map
->som_path
);
static struct hints_header
*hheader
;
static struct hints_bucket
*hbuckets
;
#define HINTS_VALID (hheader != NULL && hheader != (struct hints_header *)-1)
if ((fd
= open(_PATH_LD_HINTS
, O_RDONLY
, 0)) == -1) {
hheader
= (struct hints_header
*)-1;
addr
= mmap(0, msize
, PROT_READ
, MAP_FILE
|MAP_COPY
, fd
, 0);
if (addr
== (caddr_t
)-1) {
hheader
= (struct hints_header
*)-1;
hheader
= (struct hints_header
*)addr
;
if (HH_BADMAG(*hheader
)) {
hheader
= (struct hints_header
*)-1;
if (hheader
->hh_version
!= LD_HINTS_VERSION_1
) {
hheader
= (struct hints_header
*)-1;
if (hheader
->hh_ehints
> msize
) {
if (mmap(addr
+msize
, hheader
->hh_ehints
- msize
,
PROT_READ
, MAP_FILE
|MAP_COPY
|MAP_FIXED
,
fd
, msize
) != (caddr_t
)(addr
+msize
)) {
munmap((caddr_t
)hheader
, msize
);
hheader
= (struct hints_header
*)-1;
hbuckets
= (struct hints_bucket
*)(addr
+ hheader
->hh_hashtab
);
hstrtab
= (char *)(addr
+ hheader
->hh_strtab
);
hinthash(cp
, vmajor
, vminor
)
k
= (((k
<< 1) + (k
>> 14)) ^ (*cp
++)) & 0x3fff;
k
= (((k
<< 1) + (k
>> 14)) ^ (vmajor
*257)) & 0x3fff;
k
= (((k
<< 1) + (k
>> 14)) ^ (vminor
*167)) & 0x3fff;
findhint(name
, major
, minor
, preferred_path
)
bp
= hbuckets
+ (hinthash(name
, major
, minor
) % hheader
->hh_nbucket
);
if (bp
->hi_namex
>= hheader
->hh_strtab_sz
) {
fprintf(stderr
, "Bad name index: %#x\n", bp
->hi_namex
);
if (bp
->hi_pathx
>= hheader
->hh_strtab_sz
) {
fprintf(stderr
, "Bad path index: %#x\n", bp
->hi_pathx
);
if (strcmp(name
, hstrtab
+ bp
->hi_namex
) == 0) {
/* It's `name', check version numbers */
if (bp
->hi_major
== major
&&
(bp
->hi_ndewey
< 2 || bp
->hi_minor
== minor
)) {
if (preferred_path
== NULL
||
hstrtab
+ bp
->hi_pathx
) == 0) {
return hstrtab
+ bp
->hi_pathx
;
/* Move on to next in bucket */
bp
= &hbuckets
[bp
->hi_next
];
/* No hints available for name */
rtfindlib(name
, major
, minor
, usehints
)
char *cp
, *ld_path
= getenv("LD_LIBRARY_PATH");
if (!HINTS_VALID
|| !(*usehints
)) {
return (char *)findshlib(name
, &major
, &minor
, 0);
/* Prefer paths from LD_LIBRARY_PATH */
while ((cp
= strsep(&ld_path
, ":")) != NULL
) {
hint
= findhint(name
, major
, minor
, cp
);
/* No LD_LIBRARY_PATH, check default */
hint
= findhint(name
, major
, minor
, NULL
);
/* No hints available for name */
return (char *)findshlib(name
, &major
, &minor
, 0);
static struct somap_private dlmap_private
= {
static struct so_map dlmap
= {
* A NULL argument returns the current set of mapped objects.
if ((sodp
= (struct sod
*)malloc(sizeof(struct sod
))) == NULL
) {
sodp
->sod_name
= (long)name
;
sodp
->sod_major
= sodp
->sod_minor
= 0;
if ((smp
= map_object(sodp
, &dlmap
)) == NULL
) {
xprintf("%s: %s\n", name
, strerror(errno
));
if (LM_PRIVATE(smp
)->spd_refcount
++ == 0) {
LM_PRIVATE(smp
)->spd_flags
|= RTLD_DL
;
struct so_map
*smp
= (struct so_map
*)fd
;
xprintf("dlclose(%s): refcount = %d\n", smp
->som_path
, LM_PRIVATE(smp
)->spd_refcount
);
if (--LM_PRIVATE(smp
)->spd_refcount
!= 0)
/* Dismantle shared object map and descriptor */
struct so_map
*smp
= (struct so_map
*)fd
, *src_map
= NULL
;
* Restrict search to passed map if dlopen()ed.
if (LM_PRIVATE(smp
)->spd_flags
& RTLD_DL
)
np
= lookup(sym
, &src_map
, 1);
/* Fixup jmpslot so future calls transfer directly to target */
addr
+= (long)src_map
->som_addr
;
(void)write(1, buf
, strlen(buf
));