#import <stdlib.h>
#import <string.h>
#import <mach/mach.h>
#import <mach-o/loader.h>
#import <mach-o/nlist.h>
#import <mach-o/reloc.h>
#import <mach-o/dyld_debug.h>
#if !defined(__GONZO_BUNSEN_BEAKER__) && !defined(__HERA__) && defined(__ppc__)
#include <architecture/ppc/processor_facilities.h>
#endif
#import "images.h"
#import "mod_init_funcs.h"
#import "errors.h"
#import "lock.h"
#import "dyld_init.h"
#ifdef __ppc__
#include "fp_save_restore.h"
#endif
static enum bool delay_mod_init = TRUE;
static enum bool call_module_initializers_for_objects(
enum bool make_delayed_calls,
enum bool bind_now);
void
call_module_initializers(
enum bool make_delayed_calls,
enum bool bind_now)
{
unsigned long i;
struct library_images *q;
unsigned long *init;
#ifdef __ppc__
double fp_save_area[N_FP_REGS];
unsigned long vec_save_area[N_VEC_REGS * 4] __attribute__ ((aligned(16)));
enum bool saved_regs = FALSE;
#if !defined(__GONZO_BUNSEN_BEAKER__) && !defined(__HERA__)
int facilities_used = -1;
#endif
#endif
while(call_module_initializers_for_objects(
make_delayed_calls, bind_now) == TRUE)
;
init = NULL;
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
call_module_initializers_for_library(
q->images + i,
#ifdef __ppc__
fp_save_area,
vec_save_area,
&saved_regs,
#if !defined(__GONZO_BUNSEN_BEAKER__) && !defined(__HERA__)
&facilities_used,
#endif
#endif
make_delayed_calls,
bind_now);
}
q = q->next_images;
}while(q != NULL);
if(make_delayed_calls == TRUE)
delay_mod_init = FALSE;
#ifdef __ppc__
if(saved_regs == TRUE){
#if !defined(__GONZO_BUNSEN_BEAKER__) && !defined(__HERA__)
if(facilities_used & floatUsed)
#endif
ppc_fp_restore(fp_save_area);
#if defined(__GONZO_BUNSEN_BEAKER__) || defined(__HERA__)
if(processor_has_vec == TRUE)
#else
if(_cpu_has_altivec == TRUE && (facilities_used & vectorUsed))
#endif
ppc_vec_restore(vec_save_area);
}
#endif
}
void
call_module_initializers_for_library(
struct library_image *library_image,
#ifdef __ppc__
double *fp_save_area,
unsigned long *vec_save_area,
enum bool *saved_regs,
#if !defined(__GONZO_BUNSEN_BEAKER__) && !defined(__HERA__)
int *facilities_used,
#endif
#endif
enum bool make_delayed_calls,
enum bool bind_now)
{
unsigned long j, k;
enum link_state link_state;
struct segment_command *linkedit_segment;
struct dysymtab_command *dyst;
struct dylib_module *dylib_modules;
unsigned long addr, *init;
void (*func)(void);
linkedit_segment = library_image->image.linkedit_segment;
dyst = library_image->image.dyst;
dylib_modules = (struct dylib_module *)
(library_image->image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
init = NULL;
if(library_image->image.init != NULL)
init = (unsigned long *)(library_image->image.init->addr +
library_image->image.vmaddr_slide);
for(j = 0; j < dyst->nmodtab; j++){
link_state = GET_LINK_STATE(library_image->modules[j]);
if(link_state != REGISTERING &&
(make_delayed_calls == FALSE ||
(link_state != LINKED && link_state != FULLY_LINKED)))
continue;
if(link_state == REGISTERING)
SET_LINK_STATE(library_image->modules[j], INITIALIZING);
if(delay_mod_init == FALSE || make_delayed_calls == TRUE){
if(GET_MODINIT_STATE(library_image->modules[j]) == 0 &&
library_image->image.lazy_init == FALSE){
SET_MODINIT_STATE(library_image->modules[j]);
for(k = 0;
library_image->image.init != NULL &&
k < (dylib_modules[j].ninit_nterm & 0xffff);
k++){
addr = init[(dylib_modules[j].iinit_iterm &
0xffff) + k];
#ifdef __ppc__
#if !defined(__GONZO_BUNSEN_BEAKER__) && !defined(__HERA__)
if(*facilities_used == -1)
*facilities_used =
processor_facilities_used();
#endif
if(*saved_regs == FALSE){
#if !defined(__GONZO_BUNSEN_BEAKER__) && !defined(__HERA__)
if(*facilities_used & floatUsed)
#endif
ppc_fp_save(fp_save_area);
#if defined(__GONZO_BUNSEN_BEAKER__) || defined(__HERA__)
if(processor_has_vec == TRUE)
#else
if(_cpu_has_altivec == TRUE &&
(*facilities_used & vectorUsed))
#endif
ppc_vec_save(vec_save_area);
*saved_regs = TRUE;
}
#endif
func = (void(*)(void))addr;
release_lock();
func();
set_lock();
}
}
}
link_state = GET_LINK_STATE(library_image->modules[j]);
if(link_state == INITIALIZING){
if(bind_now == FALSE)
SET_LINK_STATE(library_image->modules[j], LINKED);
else
SET_LINK_STATE(library_image->modules[j],
FULLY_LINKED);
}
}
}
static
enum bool
call_module_initializers_for_objects(
enum bool make_delayed_calls,
enum bool bind_now)
{
unsigned long i, j, n;
enum link_state link_state;
struct object_images *p;
unsigned long slide_value, addr;
void (*func)(void);
p = &object_images;
do{
for(i = 0; i < p->nimages; i++){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state != REGISTERING &&
(make_delayed_calls == FALSE ||
(link_state != LINKED && link_state != FULLY_LINKED)))
continue;
if(link_state == REGISTERING){
SET_LINK_STATE(p->images[i].module, INITIALIZING);
if(p->images[i].image.init == NULL){
if(bind_now == FALSE)
SET_LINK_STATE(p->images[i].module, LINKED);
else
SET_LINK_STATE(p->images[i].module, FULLY_LINKED);
continue;
}
}
if(p->images[i].image.init == NULL)
continue;
if(delay_mod_init == FALSE || make_delayed_calls == TRUE){
slide_value = p->images[i].image.vmaddr_slide;
n = p->images[i].image.init->size / sizeof(unsigned long);
for(j = 0; j < n; j++){
addr = *((long *)
(p->images[i].image.init->addr + slide_value) + j);
func = (void(*)(void))addr;
release_lock();
func();
set_lock();
}
}
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state == INITIALIZING){
if(bind_now == FALSE)
SET_LINK_STATE(p->images[i].module, LINKED);
else
SET_LINK_STATE(p->images[i].module, FULLY_LINKED);
}
if(make_delayed_calls == FALSE)
return(TRUE);
}
p = p->next_images;
}while(p != NULL);
return(FALSE);
}
void
call_module_terminator_for_object(
struct object_image *object_image)
{
unsigned long i, n;
unsigned long slide_value, addr;
void (*func)(void);
if(object_image->image.term == NULL)
return;
slide_value = object_image->image.vmaddr_slide;
n = object_image->image.term->size / sizeof(unsigned long);
for(i = 0; i < n; i++){
addr = *((long *)
(object_image->image.term->addr + slide_value) + i);
func = (void(*)(void))addr;
release_lock();
func();
set_lock();
}
}
void
_dyld_call_module_initializers_for_dylib(
struct mach_header *mh_dylib_header)
{
unsigned long i, j, k;
enum link_state link_state;
struct library_images *q;
struct segment_command *linkedit_segment;
struct dysymtab_command *dyst;
struct dylib_module *dylib_modules;
unsigned long addr, *init;
void (*func)(void);
set_lock();
init = NULL;
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
if(q->images[i].image.mh != mh_dylib_header)
continue;
linkedit_segment = q->images[i].image.linkedit_segment;
dyst = q->images[i].image.dyst;
dylib_modules = (struct dylib_module *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
if(q->images[i].image.init != NULL)
init = (unsigned long *)(q->images[i].image.init->addr +
q->images[i].image.vmaddr_slide);
for(j = 0; j < dyst->nmodtab; j++){
link_state = GET_LINK_STATE(q->images[i].modules[j]);
if(link_state != REGISTERING)
continue;
if(GET_MODINIT_STATE(q->images[i].modules[j]) != 0)
continue;
SET_MODINIT_STATE(q->images[i].modules[j]);
for(k = 0; k < (dylib_modules[j].ninit_nterm & 0xffff);k++){
addr = init[(dylib_modules[j].iinit_iterm & 0xffff)+ k];
func = (void(*)(void))addr;
release_lock();
func();
set_lock();
}
}
release_lock();
return;
}
q = q->next_images;
}while(q != NULL);
release_lock();
}
void
_dyld_mod_term_funcs(
void)
{
unsigned long i, j, k;
enum bool clean_pass;
enum link_state link_state;
struct object_images *p;
unsigned long slide_value, addr, *term;
void (*func)(void);
struct library_images *q;
struct segment_command *linkedit_segment;
struct dysymtab_command *dyst;
struct dylib_module *dylib_modules;
set_lock();
top:
clean_pass = TRUE;
p = &object_images;
do{
for(i = 0; i < p->nimages; i++){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state != LINKED && link_state != FULLY_LINKED)
continue;
if(GET_MODTERM_STATE(p->images[i].module) != 0)
continue;
SET_MODTERM_STATE(p->images[i].module);
if(p->images[i].image.term == NULL)
continue;
slide_value = p->images[i].image.vmaddr_slide;
k = p->images[i].image.term->size / sizeof(unsigned long);
for(j = 0; j < k; j++){
addr = *((long *)
(p->images[i].image.term->addr + slide_value) + j);
func = (void(*)(void))addr;
release_lock();
func();
set_lock();
}
clean_pass = FALSE;
}
p = p->next_images;
}while(p != NULL);
term = NULL;
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
linkedit_segment = q->images[i].image.linkedit_segment;
dyst = q->images[i].image.dyst;
dylib_modules = (struct dylib_module *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
if(q->images[i].image.term != NULL)
term = (unsigned long *)(q->images[i].image.term->addr +
q->images[i].image.vmaddr_slide);
for(j = 0; j < dyst->nmodtab; j++){
link_state = GET_LINK_STATE(q->images[i].modules[j]);
if(link_state != LINKED && link_state != FULLY_LINKED)
continue;
if(GET_MODTERM_STATE(q->images[i].modules[j]) != 0)
continue;
SET_MODTERM_STATE(q->images[i].modules[j]);
if(q->images[i].image.term == NULL)
continue;
for(k = 0;
k < ((dylib_modules[j].ninit_nterm >> 16) & 0xffff);
k++){
addr = term[((dylib_modules[j].iinit_iterm >> 16)
& 0xffff) + k];
func = (void(*)(void))addr;
release_lock();
func();
set_lock();
clean_pass = FALSE;
}
}
}
q = q->next_images;
}while(q != NULL);
if(clean_pass == FALSE)
goto top;
release_lock();
}