#ifndef RTLD_H
#define RTLD_H
#include <dlfcn.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/param.h>
#include <sys/endian.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/exec_elf.h>
#include <sys/tls.h>
#include "rtldenv.h"
#include "link.h"
#if defined(_RTLD_SOURCE)
#if defined(__ARM_EABI__) && !defined(__ARM_DWARF_EH__)
#include "unwind.h"
#endif
#ifndef RTLD_DEFAULT_LIBRARY_PATH
#define RTLD_DEFAULT_LIBRARY_PATH "/usr/lib"
#endif
#define _PATH_LD_HINTS "/etc/ld.so.conf"
extern size_t _rtld_pagesz;
#define round_down(x) ((x) & ~(_rtld_pagesz - 1))
#define round_up(x) round_down((x) + _rtld_pagesz - 1)
#define NEW(type) ((type *) xmalloc(sizeof(type)))
#define CNEW(type) ((type *) xcalloc(sizeof(type)))
#define _rtld_donelist_init(dlp) \
((dlp)->num_alloc = _rtld_objcount, \
(dlp)->objs = alloca((dlp)->num_alloc * sizeof((dlp)->objs[0])), \
assert((dlp)->objs != NULL), \
(dlp)->num_used = 0)
typedef struct Struct_Elf_Hash {
unsigned long sysv;
unsigned long gnu;
} Elf_Hash;
#endif
struct Struct_Obj_Entry;
typedef struct Struct_Objlist_Entry {
SIMPLEQ_ENTRY(Struct_Objlist_Entry) link;
struct Struct_Obj_Entry *obj;
} Objlist_Entry;
typedef SIMPLEQ_HEAD(Struct_Objlist, Struct_Objlist_Entry) Objlist;
typedef struct Struct_Name_Entry {
SIMPLEQ_ENTRY(Struct_Name_Entry) link;
char name[1];
} Name_Entry;
typedef struct Struct_Needed_Entry {
struct Struct_Needed_Entry *next;
struct Struct_Obj_Entry *obj;
unsigned long name;
} Needed_Entry;
typedef struct _rtld_search_path_t {
struct _rtld_search_path_t *sp_next;
const char *sp_path;
size_t sp_pathlen;
} Search_Path;
typedef struct Struct_Ver_Entry {
Elf_Word hash;
u_int flags;
const char *name;
const char *file;
} Ver_Entry;
#define VER_INFO_HIDDEN 0x01
#define RTLD_MAX_ENTRY 10
#define RTLD_MAX_LIBRARY 4
#define RTLD_MAX_CTL 2
typedef struct _rtld_library_xform_t {
struct _rtld_library_xform_t *next;
char *name;
const char *ctlname;
struct {
char *value;
char *library[RTLD_MAX_LIBRARY];
} entry[RTLD_MAX_ENTRY];
} Library_Xform;
typedef void (*fptr_t)(void);
typedef struct Struct_Obj_Entry {
struct Struct_Obj_Entry *next;
char *path;
int refcount;
int dl_refcount;
caddr_t mapbase;
size_t mapsize;
size_t textsize;
Elf_Addr vaddrbase;
caddr_t relocbase;
Elf_Dyn *dynamic;
caddr_t entry;
const Elf_Phdr *phdr;
size_t phsize;
Elf_Addr *pltgot;
const Elf_Rel *rel;
const Elf_Rel *rellim;
const Elf_Rela *rela;
const Elf_Rela *relalim;
const Elf_Relr *relr;
const Elf_Relr *relrlim;
const Elf_Rel *pltrel;
const Elf_Rel *pltrellim;
const Elf_Rela *pltrela;
const Elf_Rela *pltrelalim;
const Elf_Sym *symtab;
const char *strtab;
unsigned long strsize;
#if defined(__mips__) || defined(__riscv__)
Elf_Word local_gotno;
Elf_Word symtabno;
Elf_Word gotsym;
#endif
const Elf_Symindx *buckets;
unsigned long unused1;
const Elf_Symindx *chains;
unsigned long nchains;
Search_Path *rpaths;
Needed_Entry *needed;
fptr_t init;
fptr_t fini;
u_int32_t mainprog:1,
rtld:1,
textrel:1,
symbolic:1,
printed:1,
isdynamic:1,
mainref:1,
globalref:1,
init_done:1,
init_called:1,
fini_called:1,
z_now:1,
z_nodelete:1,
z_initfirst:1,
z_noopen:1,
phdr_loaded:1,
#ifdef __alpha__
secureplt:1,
#endif
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
tls_static:1,
tls_dynamic:1,
#endif
ref_nodel:1,
sysv_hash:1,
gnu_hash:1;
struct link_map linkmap;
const char *interp;
Objlist dldags;
Objlist dagmembers;
dev_t dev;
ino_t ino;
void *ehdr;
uint32_t nbuckets;
uint32_t nbuckets_m;
uint8_t nbuckets_s1;
uint8_t nbuckets_s2;
const uint32_t *buckets_gnu;
uint32_t nbuckets_gnu;
uint32_t nbuckets_m_gnu;
uint8_t nbuckets_s1_gnu;
uint8_t nbuckets_s2_gnu;
const uint32_t *chains_gnu;
#define nchains_gnu nchains
const Elf_Addr *bloom_gnu;
uint32_t symndx_gnu;
uint32_t mask_bm_gnu;
uint32_t shift2_gnu;
size_t pathlen;
SIMPLEQ_HEAD(, Struct_Name_Entry) names;
#ifdef __powerpc__
#ifdef _LP64
Elf_Addr glink;
#else
Elf_Addr *gotptr;
#endif
#endif
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
size_t tlsindex;
void *tlsinit;
size_t tlsinitsize;
size_t tlssize;
size_t tlsoffset;
size_t tlsalign;
#endif
#ifdef GNU_RELRO
void *relro_page;
size_t relro_size;
#endif
const Elf_Verneed *verneed;
Elf_Word verneednum;
const Elf_Verdef *verdef;
Elf_Word verdefnum;
const Elf_Versym *versyms;
Ver_Entry *vertab;
int vertabnum;
fptr_t *init_array;
size_t init_arraysz;
fptr_t *fini_array;
size_t fini_arraysz;
fptr_t *preinit_array;
size_t preinit_arraysz;
size_t ifunc_remaining;
#if \
defined(__aarch64__) || \
defined(__arm__) || \
defined(__i386__) || \
defined(__powerpc__) || \
defined(__sparc__) || \
defined(__x86_64__)
#define IFUNC_NONPLT
size_t ifunc_remaining_nonplt;
#endif
size_t cxa_refcount;
#ifdef __ARM_EABI__
void *exidx_start;
size_t exidx_sz;
#endif
int finiwaiter;
int initfinilock;
int initfinilockwaiter;
int neededrefcount;
int neededwaiter;
bool relocated;
bool dlclosing;
} Obj_Entry;
typedef struct Struct_DoneList {
const Obj_Entry **objs;
unsigned int num_alloc;
unsigned int num_used;
} DoneList;
#if defined(_RTLD_SOURCE)
extern struct r_debug _rtld_debug;
extern Search_Path *_rtld_default_paths;
extern Obj_Entry *_rtld_objlist;
extern Obj_Entry **_rtld_objtail;
extern u_int _rtld_objrelocpending;
extern u_int _rtld_objcount;
extern u_int _rtld_objloads;
extern const uintptr_t _rtld_compat_obj[];
extern Obj_Entry *_rtld_objmain;
extern Obj_Entry _rtld_objself;
extern Search_Path *_rtld_paths;
extern Library_Xform *_rtld_xforms;
extern bool _rtld_trust;
extern Objlist _rtld_list_global;
extern Objlist _rtld_list_main;
extern Elf_Sym _rtld_sym_zero;
extern u_int _rtld_objgen;
#define RTLD_MODEMASK 0x3
#define SYMLOOK_IN_PLT 0x01
#define SYMLOOK_DLSYM 0x02
#define _RTLD_GLOBAL 0x01
#define _RTLD_MAIN 0x02
#define _RTLD_NOLOAD 0x04
#define _RTLD_DLOPEN 0x08
#define RTLD_STATIC_TLS_RESERVATION 64
__dso_public char *dlerror(void);
__dso_public void *dlopen(const char *, int);
__dso_public void *dlsym(void *, const char *);
__dso_public int dlclose(void *);
__dso_public int dladdr(const void *, Dl_info *);
__dso_public int dlinfo(void *, int, void *);
__dso_public int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *),
void *);
__dso_public void *_dlauxinfo(void) __pure;
__dso_public void __dl_cxa_refcount(void *addr, ssize_t delta);
__dso_public pid_t __locked_fork(int *);
#if defined(__ARM_EABI__) && !defined(__ARM_DWARF_EH__)
__dso_public _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr, int *);
#endif
void _rtld_error(const char *, ...) __printflike(1,2);
void _rtld_die(void) __dead;
void *_rtld_objmain_sym(const char *);
__dso_public void _rtld_debug_state(void) __noinline;
void _rtld_linkmap_add(Obj_Entry *);
void _rtld_linkmap_delete(Obj_Entry *);
void _rtld_objlist_push_head(Objlist *, Obj_Entry *);
void _rtld_objlist_push_tail(Objlist *, Obj_Entry *);
Objlist_Entry *_rtld_objlist_find(Objlist *, const Obj_Entry *);
void _rtld_ref_dag(Obj_Entry *);
#ifdef RTLD_LOADER
void _rtld_load_needed_enter(Obj_Entry *);
void _rtld_load_needed_exit(Obj_Entry *);
bool _rtld_wait_for_fini(Obj_Entry **, sigset_t *);
#else
static inline void
_rtld_load_needed_enter(Obj_Entry *obj)
{
obj->neededrefcount++;
}
static inline void
_rtld_load_needed_exit(Obj_Entry *obj)
{
obj->neededrefcount--;
}
static inline bool
_rtld_wait_for_fini(Obj_Entry **objp, sigset_t *mask)
{
assert((*objp)->refcount);
return false;
}
#endif
void _rtld_shared_enter(void);
void _rtld_shared_exit(void);
void _rtld_exclusive_enter(sigset_t *);
void _rtld_exclusive_exit(sigset_t *);
int _rtld_relro(const Obj_Entry *, bool);
size_t _rtld_expand_path(char *, size_t, const char *, const char *,\
const char *);
void _rtld_digest_dynamic(const char *, Obj_Entry *);
Obj_Entry *_rtld_digest_phdr(const Elf_Phdr *, int, caddr_t);
Obj_Entry *_rtld_load_object(const char *, int, sigset_t *);
int _rtld_load_needed_objects(Obj_Entry *, int, sigset_t *);
int _rtld_preload(const char *, sigset_t *);
int _rtld_map_segment_fixup(const char *, int, Elf_Ehdr *, Elf_Phdr *,
caddr_t, size_t, int);
#define OBJ_ERR (Obj_Entry *)(-1)
void _rtld_add_paths(const char *, Search_Path **, const char *);
void _rtld_process_hints(const char *, Search_Path **, Library_Xform **,
const char *);
int _rtld_sysctl(const char *, void *, size_t *);
int _rtld_do_copy_relocations(const Obj_Entry *);
int _rtld_relocate_objects(Obj_Entry *, bool);
int _rtld_relocate_nonplt_objects(Obj_Entry *);
int _rtld_relocate_plt_lazy(Obj_Entry *);
int _rtld_relocate_plt_objects(const Obj_Entry *);
void _rtld_setup_pltgot(const Obj_Entry *);
Elf_Addr _rtld_resolve_ifunc(const Obj_Entry *, const Elf_Sym *);
Elf_Addr _rtld_resolve_ifunc2(const Obj_Entry *, Elf_Addr);
void _rtld_call_ifunc(Obj_Entry *, sigset_t *, u_int);
Obj_Entry *_rtld_load_library(const char *, const Obj_Entry *, int,
sigset_t *);
const Elf_Sym *_rtld_symlook_obj(const char *, Elf_Hash *,
const Obj_Entry *, u_int, const Ver_Entry *);
const Elf_Sym *_rtld_find_symdef(unsigned long, const Obj_Entry *,
const Obj_Entry **, u_int);
const Elf_Sym *_rtld_find_plt_symdef(unsigned long, const Obj_Entry *,
const Obj_Entry **, bool);
const Elf_Sym *_rtld_symlook_list(const char *, Elf_Hash *,
const Objlist *, const Obj_Entry **, u_int, const Ver_Entry *, DoneList *);
const Elf_Sym *_rtld_symlook_default(const char *, Elf_Hash *,
const Obj_Entry *, const Obj_Entry **, u_int, const Ver_Entry *);
const Elf_Sym *_rtld_symlook_needed(const char *, Elf_Hash *,
const Needed_Entry *, const Obj_Entry **, u_int, const Ver_Entry *,
DoneList *, DoneList *);
void _rtld_object_add_name(Obj_Entry *, const char *);
int _rtld_object_match_name(const Obj_Entry *, const char *);
int _rtld_verify_object_versions(Obj_Entry *);
static __inline const Ver_Entry *
_rtld_fetch_ventry(const Obj_Entry *obj, unsigned long symnum)
{
Elf_Half vernum;
if (obj->vertab) {
vernum = VER_NDX(obj->versyms[symnum]);
if (vernum >= obj->vertabnum) {
_rtld_error("%s: symbol %s has wrong verneed value %d",
obj->path, &obj->strtab[symnum], vernum);
} else if (obj->vertab[vernum].hash) {
return &obj->vertab[vernum];
}
}
return NULL;
}
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
void *_rtld_tls_get_addr(void *, size_t, size_t);
void _rtld_tls_initial_allocation(void);
int _rtld_tls_offset_allocate(Obj_Entry *);
void _rtld_tls_offset_free(Obj_Entry *);
extern size_t _rtld_tls_dtv_generation;
extern size_t _rtld_tls_max_index;
__dso_public extern void *__tls_get_addr(void *);
#ifdef __i386__
__dso_public extern void *___tls_get_addr(void *)
__attribute__((__regparm__(1)));
#endif
#endif
struct stat;
Obj_Entry *_rtld_map_object(const char *, int, const struct stat *);
void _rtld_obj_free(Obj_Entry *);
Obj_Entry *_rtld_obj_new(void);
#ifdef RTLD_LOADER
#ifdef __HAVE_FUNCTION_DESCRIPTORS
Elf_Addr _rtld_function_descriptor_alloc(const Obj_Entry *,
const Elf_Sym *, Elf_Addr);
const void *_rtld_function_descriptor_function(const void *);
Elf_Addr _rtld_call_function_addr(const Obj_Entry *, Elf_Addr);
#else
static inline Elf_Addr
_rtld_call_function_addr(const Obj_Entry *obj, Elf_Addr addr)
{
return ((Elf_Addr(*)(void))addr)();
}
#endif
#endif
#endif
#endif