Add support for preinit, init and fini arrays. Some ABIs, in

particular on ARM, do require working init arrays.

Traditional FreeBSD crt1 calls _init and _fini of the binary, instead
of allowing runtime linker to arrange the calls.  This was probably
done to have the same crt code serve both statically and dynamically
linked binaries.  Since ABI mandates that first is called preinit
array functions, then init, and then init array functions, the init
have to be called from rtld now.

To provide binary compatibility to old FreeBSD crt1, which calls _init
itself, rtld only calls intializers and finalizers for main binary if
binary has a note indicating that new crt was used for linking.  Add
parsing of ELF notes to rtld, and cache p_osrel value since we parsed
it anyway.

The patch is inspired by init_array support for DragonflyBSD, written
by John Marino.

Reviewed by:	kan
Tested by:	andrew (arm, previous version), flo (sparc64, previous version)
MFC after:	3 weeks
This commit is contained in:
Konstantin Belousov 2012-03-11 20:03:09 +00:00
parent d1545c15cf
commit 83aa9cc00c
13 changed files with 230 additions and 14 deletions

View File

@ -10,6 +10,7 @@ SRCS= rtld_start.S \
MAN= rtld.1 MAN= rtld.1
CSTD?= gnu99 CSTD?= gnu99
CFLAGS+= -Wall -DFREEBSD_ELF -DIN_RTLD CFLAGS+= -Wall -DFREEBSD_ELF -DIN_RTLD
CFLAGS+= -I${.CURDIR}/../../lib/csu/common
.if exists(${.CURDIR}/${MACHINE_ARCH}) .if exists(${.CURDIR}/${MACHINE_ARCH})
RTLD_ARCH= ${MACHINE_ARCH} RTLD_ARCH= ${MACHINE_ARCH}
.else .else

View File

@ -58,6 +58,9 @@ reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
#define call_initfini_pointer(obj, target) \ #define call_initfini_pointer(obj, target) \
(((InitFunc)(target))()) (((InitFunc)(target))())
#define call_init_pointer(obj, target) \
(((InitArrFunc)(target))(main_argc, main_argv, environ))
#define round(size, align) \ #define round(size, align) \
(((size) + (align) - 1) & ~((align) - 1)) (((size) + (align) - 1) & ~((align) - 1))
#define calculate_first_tls_offset(size, align) \ #define calculate_first_tls_offset(size, align) \

View File

@ -48,6 +48,9 @@ Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
#define call_initfini_pointer(obj, target) \ #define call_initfini_pointer(obj, target) \
(((InitFunc)(target))()) (((InitFunc)(target))())
#define call_init_pointer(obj, target) \
(((InitArrFunc)(target))(main_argc, main_argv, environ))
#define TLS_TCB_SIZE 8 #define TLS_TCB_SIZE 8
typedef struct { typedef struct {
unsigned long ti_module; unsigned long ti_module;

View File

@ -58,6 +58,9 @@ reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
#define call_initfini_pointer(obj, target) \ #define call_initfini_pointer(obj, target) \
(((InitFunc)(target))()) (((InitFunc)(target))())
#define call_init_pointer(obj, target) \
(((InitArrFunc)(target))(main_argc, main_argv, environ))
#define round(size, align) \ #define round(size, align) \
(((size) + (align) - 1) & ~((align) - 1)) (((size) + (align) - 1) & ~((align) - 1))
#define calculate_first_tls_offset(size, align) \ #define calculate_first_tls_offset(size, align) \

View File

@ -586,6 +586,18 @@ call_initfini_pointer(const Obj_Entry *obj, Elf_Addr target)
((InitFunc) &fptr)(); ((InitFunc) &fptr)();
} }
void
call_init_pointer(const Obj_Entry *obj, Elf_Addr target)
{
struct fptr fptr;
fptr.gp = (Elf_Addr) obj->pltgot;
fptr.target = target;
dbg(" initfini: target=%p, gp=%p",
(void *) fptr.target, (void *) fptr.gp);
((InitArrFunc) &fptr)(main_argc, main_argv, environ);
}
/* Initialize the special PLT entries. */ /* Initialize the special PLT entries. */
void void
init_pltgot(Obj_Entry *obj) init_pltgot(Obj_Entry *obj)

View File

@ -52,6 +52,7 @@ Elf_Addr reloc_jmpslot(Elf_Addr *, Elf_Addr, const struct Struct_Obj_Entry *,
const struct Struct_Obj_Entry *, const Elf_Rel *); const struct Struct_Obj_Entry *, const Elf_Rel *);
void *make_function_pointer(const Elf_Sym *, const struct Struct_Obj_Entry *); void *make_function_pointer(const Elf_Sym *, const struct Struct_Obj_Entry *);
void call_initfini_pointer(const struct Struct_Obj_Entry *, Elf_Addr); void call_initfini_pointer(const struct Struct_Obj_Entry *, Elf_Addr);
void call_init_pointer(const struct Struct_Obj_Entry *, Elf_Addr);
#define TLS_TCB_SIZE 16 #define TLS_TCB_SIZE 16

View File

@ -86,6 +86,8 @@ map_object(int fd, const char *path, const struct stat *sb)
Elf_Word stack_flags; Elf_Word stack_flags;
Elf_Addr relro_page; Elf_Addr relro_page;
size_t relro_size; size_t relro_size;
Elf_Addr note_start;
Elf_Addr note_end;
hdr = get_elf_header(fd, path); hdr = get_elf_header(fd, path);
if (hdr == NULL) if (hdr == NULL)
@ -104,6 +106,8 @@ map_object(int fd, const char *path, const struct stat *sb)
phdr_vaddr = 0; phdr_vaddr = 0;
relro_page = 0; relro_page = 0;
relro_size = 0; relro_size = 0;
note_start = 0;
note_end = 0;
segs = alloca(sizeof(segs[0]) * hdr->e_phnum); segs = alloca(sizeof(segs[0]) * hdr->e_phnum);
stack_flags = RTLD_DEFAULT_STACK_PF_EXEC | PF_R | PF_W; stack_flags = RTLD_DEFAULT_STACK_PF_EXEC | PF_R | PF_W;
while (phdr < phlimit) { while (phdr < phlimit) {
@ -143,6 +147,12 @@ map_object(int fd, const char *path, const struct stat *sb)
relro_page = phdr->p_vaddr; relro_page = phdr->p_vaddr;
relro_size = phdr->p_memsz; relro_size = phdr->p_memsz;
break; break;
case PT_NOTE:
note_start = (Elf_Addr)obj->relocbase + phdr->p_offset;
note_end = note_start + phdr->p_filesz;
digest_notes(obj, note_start, note_end);
break;
} }
++phdr; ++phdr;

View File

@ -49,6 +49,9 @@ Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
#define call_initfini_pointer(obj, target) \ #define call_initfini_pointer(obj, target) \
(((InitFunc)(target))()) (((InitFunc)(target))())
#define call_init_pointer(obj, target) \
(((InitArrFunc)(target))(main_argc, main_argv, environ))
typedef struct { typedef struct {
unsigned long ti_module; unsigned long ti_module;
unsigned long ti_offset; unsigned long ti_offset;

View File

@ -48,6 +48,9 @@ Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
#define call_initfini_pointer(obj, target) \ #define call_initfini_pointer(obj, target) \
(((InitFunc)(target))()) (((InitFunc)(target))())
#define call_init_pointer(obj, target) \
(((InitArrFunc)(target))(main_argc, main_argv, environ))
/* /*
* Lazy binding entry point, called via PLT. * Lazy binding entry point, called via PLT.
*/ */

View File

@ -48,6 +48,9 @@ Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
#define call_initfini_pointer(obj, target) \ #define call_initfini_pointer(obj, target) \
(((InitFunc)(target))()) (((InitFunc)(target))())
#define call_init_pointer(obj, target) \
(((InitArrFunc)(target))(main_argc, main_argv, environ))
/* /*
* Lazy binding entry point, called via PLT. * Lazy binding entry point, called via PLT.
*/ */

View File

@ -61,6 +61,7 @@
#include "libmap.h" #include "libmap.h"
#include "rtld_tls.h" #include "rtld_tls.h"
#include "rtld_printf.h" #include "rtld_printf.h"
#include "notes.h"
#ifndef COMPAT_32BIT #ifndef COMPAT_32BIT
#define PATH_RTLD "/libexec/ld-elf.so.1" #define PATH_RTLD "/libexec/ld-elf.so.1"
@ -139,6 +140,7 @@ static void ref_dag(Obj_Entry *);
static int origin_subst_one(char **, const char *, const char *, static int origin_subst_one(char **, const char *, const char *,
const char *, char *); const char *, char *);
static char *origin_subst(const char *, const char *); static char *origin_subst(const char *, const char *);
static void preinit_main(void);
static int rtld_verify_versions(const Objlist *); static int rtld_verify_versions(const Objlist *);
static int rtld_verify_object_versions(Obj_Entry *); static int rtld_verify_object_versions(Obj_Entry *);
static void object_add_name(Obj_Entry *, const char *); static void object_add_name(Obj_Entry *, const char *);
@ -204,6 +206,12 @@ static int max_stack_flags;
char *__progname; char *__progname;
char **environ; char **environ;
/*
* Used to pass argc, argv to init functions.
*/
int main_argc;
char **main_argv;
/* /*
* Globals to control TLS allocation. * Globals to control TLS allocation.
*/ */
@ -335,6 +343,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
__progname = obj_rtld.path; __progname = obj_rtld.path;
argv0 = argv[0] != NULL ? argv[0] : "(null)"; argv0 = argv[0] != NULL ? argv[0] : "(null)";
environ = env; environ = env;
main_argc = argc;
main_argv = argv;
trust = !issetugid(); trust = !issetugid();
@ -458,8 +468,6 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
obj_tail = &obj_main->next; obj_tail = &obj_main->next;
obj_count++; obj_count++;
obj_loads++; obj_loads++;
/* Make sure we don't call the main program's init and fini functions. */
obj_main->init = obj_main->fini = (Elf_Addr)NULL;
/* Initialize a fake symbol for resolving undefined weak references. */ /* Initialize a fake symbol for resolving undefined weak references. */
sym_zero.st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE); sym_zero.st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
@ -551,7 +559,20 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
ld_bind_now != NULL && *ld_bind_now != '\0', NULL) == -1) ld_bind_now != NULL && *ld_bind_now != '\0', NULL) == -1)
die(); die();
if (!obj_main->crt_no_init) {
/*
* Make sure we don't call the main program's init and fini
* functions for binaries linked with old crt1 which calls
* _init itself.
*/
obj_main->init = obj_main->fini = (Elf_Addr)NULL;
obj_main->preinit_array = obj_main->init_array =
obj_main->fini_array = (Elf_Addr)NULL;
}
wlock_acquire(rtld_bind_lock, &lockstate); wlock_acquire(rtld_bind_lock, &lockstate);
if (obj_main->crt_no_init)
preinit_main();
objlist_call_init(&initlist, &lockstate); objlist_call_init(&initlist, &lockstate);
objlist_clear(&initlist); objlist_clear(&initlist);
dbg("loading filtees"); dbg("loading filtees");
@ -936,10 +957,34 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
obj->init = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr); obj->init = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr);
break; break;
case DT_PREINIT_ARRAY:
obj->preinit_array = (Elf_Addr)(obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_PREINIT_ARRAYSZ:
obj->preinit_array_num = dynp->d_un.d_val / sizeof(Elf_Addr);
break;
case DT_INIT_ARRAY:
obj->init_array = (Elf_Addr)(obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_INIT_ARRAYSZ:
obj->init_array_num = dynp->d_un.d_val / sizeof(Elf_Addr);
break;
case DT_FINI: case DT_FINI:
obj->fini = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr); obj->fini = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr);
break; break;
case DT_FINI_ARRAY:
obj->fini_array = (Elf_Addr)(obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_FINI_ARRAYSZ:
obj->fini_array_num = dynp->d_un.d_val / sizeof(Elf_Addr);
break;
/* /*
* Don't process DT_DEBUG on MIPS as the dynamic section * Don't process DT_DEBUG on MIPS as the dynamic section
* is mapped read-only. DT_MIPS_RLD_MAP is used instead. * is mapped read-only. DT_MIPS_RLD_MAP is used instead.
@ -1065,6 +1110,7 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
Obj_Entry *obj; Obj_Entry *obj;
const Elf_Phdr *phlimit = phdr + phnum; const Elf_Phdr *phlimit = phdr + phnum;
const Elf_Phdr *ph; const Elf_Phdr *ph;
Elf_Addr note_start, note_end;
int nsegs = 0; int nsegs = 0;
obj = obj_new(); obj = obj_new();
@ -1120,6 +1166,12 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
obj->relro_page = obj->relocbase + trunc_page(ph->p_vaddr); obj->relro_page = obj->relocbase + trunc_page(ph->p_vaddr);
obj->relro_size = round_page(ph->p_memsz); obj->relro_size = round_page(ph->p_memsz);
break; break;
case PT_NOTE:
note_start = (Elf_Addr)obj->relocbase + ph->p_vaddr;
note_end = note_start + ph->p_filesz;
digest_notes(obj, note_start, note_end);
break;
} }
} }
if (nsegs < 1) { if (nsegs < 1) {
@ -1131,6 +1183,44 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
return obj; return obj;
} }
void
digest_notes(Obj_Entry *obj, Elf_Addr note_start, Elf_Addr note_end)
{
const Elf_Note *note;
const char *note_name;
uintptr_t p;
for (note = (const Elf_Note *)note_start; (Elf_Addr)note < note_end;
note = (const Elf_Note *)((const char *)(note + 1) +
roundup2(note->n_namesz, sizeof(Elf32_Addr)) +
roundup2(note->n_descsz, sizeof(Elf32_Addr)))) {
if (note->n_namesz != sizeof(NOTE_FREEBSD_VENDOR) ||
note->n_descsz != sizeof(int32_t))
continue;
if (note->n_type != ABI_NOTETYPE &&
note->n_type != CRT_NOINIT_NOTETYPE)
continue;
note_name = (const char *)(note + 1);
if (strncmp(NOTE_FREEBSD_VENDOR, note_name,
sizeof(NOTE_FREEBSD_VENDOR)) != 0)
continue;
switch (note->n_type) {
case ABI_NOTETYPE:
/* FreeBSD osrel note */
p = (uintptr_t)(note + 1);
p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
obj->osrel = *(const int32_t *)(p);
dbg("note osrel %d", obj->osrel);
break;
case CRT_NOINIT_NOTETYPE:
/* FreeBSD 'crt does not call init' note */
obj->crt_no_init = true;
dbg("note crt_no_init");
break;
}
}
}
static Obj_Entry * static Obj_Entry *
dlcheck(void *handle) dlcheck(void *handle)
{ {
@ -1504,11 +1594,13 @@ initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list)
initlist_add_neededs(obj->needed, list); initlist_add_neededs(obj->needed, list);
/* Add the object to the init list. */ /* Add the object to the init list. */
if (obj->init != (Elf_Addr)NULL) if (obj->preinit_array != (Elf_Addr)NULL || obj->init != (Elf_Addr)NULL ||
obj->init_array != (Elf_Addr)NULL)
objlist_push_tail(list, obj); objlist_push_tail(list, obj);
/* Add the object to the global fini list in the reverse order. */ /* Add the object to the global fini list in the reverse order. */
if (obj->fini != (Elf_Addr)NULL && !obj->on_fini_list) { if ((obj->fini != (Elf_Addr)NULL || obj->fini_array != (Elf_Addr)NULL)
&& !obj->on_fini_list) {
objlist_push_head(&list_fini, obj); objlist_push_head(&list_fini, obj);
obj->on_fini_list = true; obj->on_fini_list = true;
} }
@ -1796,6 +1888,27 @@ obj_from_addr(const void *addr)
return NULL; return NULL;
} }
static void
preinit_main(void)
{
Elf_Addr *preinit_addr;
int index;
preinit_addr = (Elf_Addr *)obj_main->preinit_array;
if (preinit_addr == (Elf_Addr)NULL)
return;
for (index = 0; index < obj_main->preinit_array_num; index++) {
if (preinit_addr[index] != 0 && preinit_addr[index] != 1) {
dbg("calling preinit function for %s at %p", obj_main->path,
(void *)preinit_addr[index]);
LD_UTRACE(UTRACE_INIT_CALL, obj_main, (void *)preinit_addr[index],
0, 0, obj_main->path);
call_init_pointer(obj_main, preinit_addr[index]);
}
}
}
/* /*
* Call the finalization functions for each of the objects in "list" * Call the finalization functions for each of the objects in "list"
* belonging to the DAG of "root" and referenced once. If NULL "root" * belonging to the DAG of "root" and referenced once. If NULL "root"
@ -1808,6 +1921,8 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate)
{ {
Objlist_Entry *elm; Objlist_Entry *elm;
char *saved_msg; char *saved_msg;
Elf_Addr *fini_addr;
int index;
assert(root == NULL || root->refcount == 1); assert(root == NULL || root->refcount == 1);
@ -1821,10 +1936,6 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate)
if (root != NULL && (elm->obj->refcount != 1 || if (root != NULL && (elm->obj->refcount != 1 ||
objlist_find(&root->dagmembers, elm->obj) == NULL)) objlist_find(&root->dagmembers, elm->obj) == NULL))
continue; continue;
dbg("calling fini function for %s at %p", elm->obj->path,
(void *)elm->obj->fini);
LD_UTRACE(UTRACE_FINI_CALL, elm->obj, (void *)elm->obj->fini, 0, 0,
elm->obj->path);
/* Remove object from fini list to prevent recursive invocation. */ /* Remove object from fini list to prevent recursive invocation. */
STAILQ_REMOVE(list, elm, Struct_Objlist_Entry, link); STAILQ_REMOVE(list, elm, Struct_Objlist_Entry, link);
/* /*
@ -1835,7 +1946,31 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate)
* called. * called.
*/ */
lock_release(rtld_bind_lock, lockstate); lock_release(rtld_bind_lock, lockstate);
call_initfini_pointer(elm->obj, elm->obj->fini);
/*
* It is legal to have both DT_FINI and DT_FINI_ARRAY defined.
* When this happens, DT_FINI_ARRAY is processed first.
*/
fini_addr = (Elf_Addr *)elm->obj->fini_array;
if (fini_addr != NULL && elm->obj->fini_array_num > 0) {
for (index = elm->obj->fini_array_num - 1; index >= 0;
index--) {
if (fini_addr[index] != 0 && fini_addr[index] != 1) {
dbg("calling fini function for %s at %p",
elm->obj->path, (void *)fini_addr[index]);
LD_UTRACE(UTRACE_FINI_CALL, elm->obj,
(void *)fini_addr[index], 0, 0, elm->obj->path);
call_initfini_pointer(elm->obj, fini_addr[index]);
}
}
}
if (elm->obj->fini != (Elf_Addr)NULL) {
dbg("calling fini function for %s at %p", elm->obj->path,
(void *)elm->obj->fini);
LD_UTRACE(UTRACE_FINI_CALL, elm->obj, (void *)elm->obj->fini,
0, 0, elm->obj->path);
call_initfini_pointer(elm->obj, elm->obj->fini);
}
wlock_acquire(rtld_bind_lock, lockstate); wlock_acquire(rtld_bind_lock, lockstate);
/* No need to free anything if process is going down. */ /* No need to free anything if process is going down. */
if (root != NULL) if (root != NULL)
@ -1862,6 +1997,8 @@ objlist_call_init(Objlist *list, RtldLockState *lockstate)
Objlist_Entry *elm; Objlist_Entry *elm;
Obj_Entry *obj; Obj_Entry *obj;
char *saved_msg; char *saved_msg;
Elf_Addr *init_addr;
int index;
/* /*
* Clean init_scanned flag so that objects can be rechecked and * Clean init_scanned flag so that objects can be rechecked and
@ -1879,10 +2016,6 @@ objlist_call_init(Objlist *list, RtldLockState *lockstate)
STAILQ_FOREACH(elm, list, link) { STAILQ_FOREACH(elm, list, link) {
if (elm->obj->init_done) /* Initialized early. */ if (elm->obj->init_done) /* Initialized early. */
continue; continue;
dbg("calling init function for %s at %p", elm->obj->path,
(void *)elm->obj->init);
LD_UTRACE(UTRACE_INIT_CALL, elm->obj, (void *)elm->obj->init, 0, 0,
elm->obj->path);
/* /*
* Race: other thread might try to use this object before current * Race: other thread might try to use this object before current
* one completes the initilization. Not much can be done here * one completes the initilization. Not much can be done here
@ -1890,7 +2023,30 @@ objlist_call_init(Objlist *list, RtldLockState *lockstate)
*/ */
elm->obj->init_done = true; elm->obj->init_done = true;
lock_release(rtld_bind_lock, lockstate); lock_release(rtld_bind_lock, lockstate);
call_initfini_pointer(elm->obj, elm->obj->init);
/*
* It is legal to have both DT_INIT and DT_INIT_ARRAY defined.
* When this happens, DT_INIT is processed first.
*/
if (elm->obj->init != (Elf_Addr)NULL) {
dbg("calling init function for %s at %p", elm->obj->path,
(void *)elm->obj->init);
LD_UTRACE(UTRACE_INIT_CALL, elm->obj, (void *)elm->obj->init,
0, 0, elm->obj->path);
call_initfini_pointer(elm->obj, elm->obj->init);
}
init_addr = (Elf_Addr *)elm->obj->init_array;
if (init_addr != (Elf_Addr)NULL) {
for (index = 0; index < elm->obj->init_array_num; index++) {
if (init_addr[index] != 0 && init_addr[index] != 1) {
dbg("calling init function for %s at %p", elm->obj->path,
(void *)init_addr[index]);
LD_UTRACE(UTRACE_INIT_CALL, elm->obj,
(void *)init_addr[index], 0, 0, elm->obj->path);
call_init_pointer(elm->obj, init_addr[index]);
}
}
}
wlock_acquire(rtld_bind_lock, lockstate); wlock_acquire(rtld_bind_lock, lockstate);
} }
errmsg_restore(saved_msg); errmsg_restore(saved_msg);

View File

@ -71,6 +71,10 @@ extern size_t tls_static_space;
extern int tls_dtv_generation; extern int tls_dtv_generation;
extern int tls_max_index; extern int tls_max_index;
extern int main_argc;
extern char **main_argv;
extern char **environ;
struct stat; struct stat;
struct Struct_Obj_Entry; struct Struct_Obj_Entry;
@ -84,6 +88,7 @@ typedef STAILQ_HEAD(Struct_Objlist, Struct_Objlist_Entry) Objlist;
/* Types of init and fini functions */ /* Types of init and fini functions */
typedef void (*InitFunc)(void); typedef void (*InitFunc)(void);
typedef void (*InitArrFunc)(int, char **, char **);
/* Lists of shared object dependencies */ /* Lists of shared object dependencies */
typedef struct Struct_Needed_Entry { typedef struct Struct_Needed_Entry {
@ -213,6 +218,14 @@ typedef struct Struct_Obj_Entry {
Elf_Addr init; /* Initialization function to call */ Elf_Addr init; /* Initialization function to call */
Elf_Addr fini; /* Termination function to call */ Elf_Addr fini; /* Termination function to call */
Elf_Addr preinit_array; /* Pre-initialization array of functions */
Elf_Addr init_array; /* Initialization array of functions */
Elf_Addr fini_array; /* Termination array of functions */
int preinit_array_num; /* Number of entries in preinit_array */
int init_array_num; /* Number of entries in init_array */
int fini_array_num; /* Number of entries in fini_array */
int32_t osrel; /* OSREL note value */
bool mainprog : 1; /* True if this is the main program */ bool mainprog : 1; /* True if this is the main program */
bool rtld : 1; /* True if this is the dynamic linker */ bool rtld : 1; /* True if this is the dynamic linker */
@ -235,6 +248,7 @@ typedef struct Struct_Obj_Entry {
bool filtees_loaded : 1; /* Filtees loaded */ bool filtees_loaded : 1; /* Filtees loaded */
bool irelative : 1; /* Object has R_MACHDEP_IRELATIVE relocs */ bool irelative : 1; /* Object has R_MACHDEP_IRELATIVE relocs */
bool gnu_ifunc : 1; /* Object has references to STT_GNU_IFUNC */ bool gnu_ifunc : 1; /* Object has references to STT_GNU_IFUNC */
bool crt_no_init : 1; /* Object' crt does not call _init/_fini */
struct link_map linkmap; /* For GDB and dlinfo() */ struct link_map linkmap; /* For GDB and dlinfo() */
Objlist dldags; /* Object belongs to these dlopened DAGs (%) */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */
@ -319,6 +333,7 @@ const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *,
const Obj_Entry **, int, SymCache *, struct Struct_RtldLockState *); const Obj_Entry **, int, SymCache *, struct Struct_RtldLockState *);
void init_pltgot(Obj_Entry *); void init_pltgot(Obj_Entry *);
void lockdflt_init(void); void lockdflt_init(void);
void digest_notes(Obj_Entry *, Elf_Addr, Elf_Addr);
void obj_free(Obj_Entry *); void obj_free(Obj_Entry *);
Obj_Entry *obj_new(void); Obj_Entry *obj_new(void);
void _rtld_bind_start(void); void _rtld_bind_start(void);

View File

@ -50,6 +50,9 @@ Elf_Addr reloc_jmpslot(Elf_Addr *, Elf_Addr,
#define call_initfini_pointer(obj, target) \ #define call_initfini_pointer(obj, target) \
(((InitFunc)(target))()) (((InitFunc)(target))())
#define call_init_pointer(obj, target) \
(((InitArrFunc)(target))(main_argc, main_argv, environ))
#define round(size, align) \ #define round(size, align) \
(((size) + (align) - 1) & ~((align) - 1)) (((size) + (align) - 1) & ~((align) - 1))
#define calculate_first_tls_offset(size, align) \ #define calculate_first_tls_offset(size, align) \