#ifdef SHLIB
#include "shlib.h"
#undef moninitrld
#endif
#ifdef RLD
#include <mach-o/loader.h>
#ifndef __OPENSTEP__
extern const struct segment_command *getsegbyname(const char *segname);
extern const struct section *getsectbynamefromheader(
const struct mach_header *mhp,
const char *segname,
const char *sectname);
#endif
#if !(defined(KLD) && defined(__STATIC__))
#include <libc.h>
#include <stdio.h>
#include <mach/mach.h>
#include "stuff/vm_flush_cache.h"
#else
#include <stdlib.h>
#include <unistd.h>
#include <mach/kern_return.h>
#include <mach/vm_map.h>
#endif
#include <setjmp.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "stuff/openstep_mach.h"
#include <mach-o/fat.h>
#include <mach-o/nlist.h>
#ifdef KLD
#include <mach-o/kld.h>
#else
#include <mach-o/rld.h>
#include <streams/streams.h>
#include <objc/zone.h>
#endif
#include <mach-o/rld_state.h>
#include <mach-o/ldsyms.h>
#define __darwin_i386_float_state i386_float_state
#include "stuff/arch.h"
#include "stuff/best_arch.h"
#include "ld.h"
#include "live_refs.h"
#include "objects.h"
#include "sections.h"
#include "symbols.h"
#include "pass1.h"
#include "layout.h"
#include "pass2.h"
#include "sets.h"
#ifdef SA_RLD
#include "mach-o/sarld.h"
#endif
#ifdef KLD
#include "mach-o/kld.h"
#endif
#if defined(SA_RLD)
#include "standalone/libsa.h"
#endif
#ifndef __OPENSTEP__
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
#include <crt_externs.h>
#endif
#else
#ifdef __DYNAMIC__
#include "mach-o/dyld.h"
#endif
#endif
__private_extern__
unsigned long (*address_func)(unsigned long size, unsigned long headers_size) =
NULL;
static
enum strip_levels kld_requested_strip_level = STRIP_ALL;
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
static void (*rld_monaddition)(char *lowpc, char *highpc) = NULL;
#endif
__private_extern__ long RLD_DEBUG_OUTPUT_FILENAME_flag = 0;
#ifndef KLD
static NXStream *error_stream = NULL;
#endif
#if !defined(SA_RLD) && !defined(KLD)
static NXZone *zonep = NULL;
#endif
static jmp_buf rld_env;
static volatile int fatals = 0;
__private_extern__ char *base_name = NULL;
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
static enum bool rld_maintain_states = FALSE;
static unsigned long rld_nallocated_states = 0;
static unsigned long rld_nloaded_states = 0;
static struct rld_loaded_state *rld_loaded_state = NULL;
static void rld_loaded_state_changed(void);
#define NSTATES_INCREMENT 10
#endif
#ifdef KLD
void
kld_set_byteorder(enum NXByteOrder order)
{
switch (order) {
case NX_BigEndian:
target_byte_sex = BIG_ENDIAN_BYTE_SEX;
break;
case NX_LittleEndian:
target_byte_sex = LITTLE_ENDIAN_BYTE_SEX;
break;
default:
target_byte_sex = UNKNOWN_BYTE_SEX;
}
}
#endif
#ifdef KLD
static long internal_kld_load(
#else
static long internal_rld_load(
NXStream *stream,
#endif
struct mach_header **header_addr,
const char * const *object_filenames,
const char *output_filename,
const char *file_name,
const char *obj_addr,
long obj_size);
#ifdef KLD
static long internal_kld_unload(
#else
static long internal_rld_unload(
NXStream *stream,
#endif
enum bool internal_cleanup);
#if !defined(SA_RLD) && !defined(KLD)
static long internal_rld_load_basefile(
NXStream *stream,
const char *base_filename,
char *base_addr,
long base_size);
#endif
#if defined(KLD)
static long internal_kld_load_basefile(
const char *base_filename,
char *base_addr,
long base_size);
#endif
#if !defined(SA_RLD) && !defined(KLD)
long
rld_load(
NXStream *stream,
struct mach_header **header_addr,
const char * const *object_filenames,
const char *output_filename)
{
return(internal_rld_load(stream, header_addr, object_filenames,
output_filename, NULL, NULL, 0));
}
#endif
#if defined(KLD) && defined(__DYNAMIC__)
long
kld_load(
struct mach_header **header_addr,
const char *object_filename,
const char *output_filename)
{
const char *object_filenames[2];
object_filenames[0] = object_filename;
object_filenames[1] = NULL;
return(internal_kld_load(header_addr, object_filenames,
output_filename, NULL, NULL, 0));
}
long
kld_load_from_memory(
struct mach_header **header_addr,
const char *object_name,
char *object_addr,
long object_size,
const char *output_filename)
{
return(internal_kld_load(header_addr, NULL, output_filename,
object_name, object_addr, object_size));
}
#endif
#if !defined(SA_RLD) && !defined(KLD)
long
rld_load_from_memory(
NXStream *stream,
struct mach_header **header_addr,
const char *object_name,
char *object_addr,
long object_size,
const char *output_filename)
{
return(internal_rld_load(stream, header_addr, NULL, output_filename,
object_name, object_addr, object_size));
}
#endif
#if defined(KLD) && defined(__STATIC__)
long
kld_load_from_memory(
struct mach_header **header_addr,
const char *object_name,
char *object_addr,
long object_size)
{
return(internal_kld_load(header_addr, NULL, NULL,
object_name, object_addr, object_size));
}
#endif
static
long
#ifdef KLD
internal_kld_load(
#else
internal_rld_load(
NXStream *stream,
#endif
struct mach_header **header_addr,
const char * const *object_filenames,
const char *output_filename,
const char *file_name,
const char *obj_addr,
long obj_size)
{
#if !(defined(KLD) && defined(__STATIC__))
kern_return_t r;
#endif
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
int i, n;
int fd;
long symbol_size, deallocate_size;
char dir[MAXPATHLEN];
long dir_len;
const struct section *s;
void (**routines)(void);
dir[0] = '\0';
dir_len = 0;
#endif
#ifndef KLD
error_stream = stream;
#endif
if(header_addr != NULL)
*header_addr = NULL;
if(fatals == 1){
print("previous fatal errors occured, can no longer succeed");
return(0);
}
if(setjmp(rld_env) != 0){
if(fatals == 0)
#ifdef KLD
internal_kld_unload(TRUE);
#else
internal_rld_unload(stream, TRUE);
#endif
return(0);
}
#ifdef KLD
progname = "kld()";
#else
progname = "rld()";
#endif
host_pagesize = getpagesize();
host_byte_sex = get_host_byte_sex();
force_cpusubtype_ALL = TRUE;
filetype = MH_OBJECT;
flush = FALSE;
nmerged_symbols = 0;
merged_string_size = 0;
nlocal_symbols = 0;
local_string_size = 0;
strip_base_symbols = TRUE;
if(output_filename != NULL)
strip_level = STRIP_NONE;
else
strip_level = kld_requested_strip_level;
errors = 0;
#if !defined(SA_RLD) && !(defined(KLD) && defined(__DYNAMIC__))
if(base_obj == NULL){
#if !defined(__OPENSTEP__) && !defined(KLD)
static char ***NXArgv_pointer = NULL;
static struct mach_header *_mh_execute_header_pointer = NULL;
struct segment_command *sg;
if(NXArgv_pointer == NULL)
NXArgv_pointer = _NSGetArgv();
if(_mh_execute_header_pointer == NULL)
_mh_execute_header_pointer = _NSGetMachExecuteHeader();
sg = (struct segment_command *)getsegbyname(SEG_LINKEDIT);
if(sg != NULL)
merge_base_program((*NXArgv_pointer)[0],
_mh_execute_header_pointer, sg,
NULL, 0, NULL, 0);
#else
struct segment_command *sg;
#ifndef __DYNAMIC__
#ifdef KLD
#ifndef _LIBSA_STDLIB_H_
__private_extern__ const char *kld_basefile_name;
#endif
#else
extern char **NXArgv;
#endif
#else
static char ***NXArgv_pointer = NULL;
static struct mach_header *_mh_execute_header_pointer = NULL;
if(NXArgv_pointer == NULL)
_dyld_lookup_and_bind("_NXArgv",
(unsigned long *)&NXArgv_pointer, NULL);
if(_mh_execute_header_pointer == NULL)
_dyld_lookup_and_bind("__mh_execute_header",
(unsigned long *)&_mh_execute_header_pointer, NULL);
#endif
sg = (struct segment_command *)getsegbyname(SEG_LINKEDIT);
if(sg != NULL)
#ifndef __DYNAMIC__
#ifdef KLD
merge_base_program(kld_basefile_name,
(struct mach_header *)&_mh_execute_header, sg,
NULL, 0, NULL, 0);
#else
merge_base_program(
NXArgv[0], (struct mach_header *)&_mh_execute_header, sg,
NULL, 0, NULL, 0);
#endif
#else
merge_base_program((*NXArgv_pointer)[0],
_mh_execute_header_pointer, sg,
NULL, 0, NULL, 0);
#endif
#endif
if (target_byte_sex == UNKNOWN_BYTE_SEX)
target_byte_sex = host_byte_sex;
if(errors){
fatals = 1;
return(0);
}
#ifndef KLD
rld_maintain_states = TRUE;
#endif
}
#endif
new_set();
zero_merged_sections_sizes();
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
if(file_name == NULL){
for(i = 0; object_filenames[i] != NULL; i++)
pass1((char *)object_filenames[i], FALSE, FALSE, FALSE, FALSE,
FALSE);
}
else
#endif
{
cur_obj = new_object_file();
cur_obj->file_name = allocate(strlen(file_name) + 1);
strcpy(cur_obj->file_name, file_name);
cur_obj->user_obj_addr = TRUE;
cur_obj->obj_addr = (char *)obj_addr;
cur_obj->obj_size = obj_size;
merge(FALSE, FALSE, FALSE);
}
if(errors){
#ifdef KLD
internal_kld_unload(TRUE);
#else
internal_rld_unload(stream, TRUE);
#endif
return(0);
}
if(output_filename == RLD_DEBUG_OUTPUT_FILENAME)
RLD_DEBUG_OUTPUT_FILENAME_flag = 1;
else
RLD_DEBUG_OUTPUT_FILENAME_flag = 0;
layout();
if(errors){
#ifdef KLD
internal_kld_unload(TRUE);
#else
internal_rld_unload(stream, TRUE);
#endif
return(0);
}
pass2();
if(errors){
#ifdef KLD
internal_kld_unload(TRUE);
#else
internal_rld_unload(stream, TRUE);
#endif
return(0);
}
reset_merged_sections();
clean_objects();
clean_archives_and_fats();
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
if(output_filename != NULL &&
output_filename != RLD_DEBUG_OUTPUT_FILENAME){
symbol_size = output_symtab_info.symtab_command.nsyms *
sizeof(struct nlist) +
output_symtab_info.symtab_command.strsize;
(void)unlink(output_filename);
if((fd = open(output_filename, O_WRONLY | O_CREAT | O_TRUNC,
0666)) == -1){
system_error("can't create output file: %s", output_filename);
#ifdef KLD
internal_kld_unload(TRUE);
#else
internal_rld_unload(stream, TRUE);
#endif
return(0);
}
else {
if(write(fd, output_addr, output_size + symbol_size) !=
(int)(output_size + symbol_size)){
system_error("can't write output file: %s",output_filename);
#ifdef KLD
internal_kld_unload(TRUE);
#else
internal_rld_unload(stream, TRUE);
#endif
return(0);
}
if(close(fd) == -1){
system_error("can't close output file: %s",output_filename);
#ifdef KLD
internal_kld_unload(TRUE);
#else
internal_rld_unload(stream, TRUE);
#endif
return(0);
}
}
if (strip_level == STRIP_ALL)
deallocate_size = rnd(output_size + symbol_size, host_pagesize) -
rnd(output_size, host_pagesize);
else {
deallocate_size = 0;
sets[cur_set].output_size += symbol_size;
}
if(deallocate_size > 0){
if((r = vm_deallocate(mach_task_self(),
(vm_address_t)(output_addr +
rnd(output_size, host_pagesize)),
deallocate_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() buffer for output "
"file's symbol table");
#ifdef RLD_VM_ALLOC_DEBUG
print("rld() vm_deallocate: addr = 0x%0x size = 0x%x\n",
(unsigned int)(output_addr +
rnd(output_size, host_pagesize)),
(unsigned int)deallocate_size);
#endif
}
}
#endif
if(header_addr != NULL)
*header_addr = (struct mach_header *)output_addr;
#if !(defined(KLD) && defined(__STATIC__))
if((r = vm_flush_cache(mach_task_self(), (vm_address_t)output_addr,
output_size)) != KERN_SUCCESS)
#ifndef SA_RLD
mach_fatal(r, "can't vm_flush_cache() output buffer");
#else
fatal("can't vm_flush_cache() output buffer");
#endif
#endif
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
if(rld_maintain_states == TRUE){
if(rld_nloaded_states + 1 >= rld_nallocated_states){
rld_loaded_state = reallocate(rld_loaded_state,
sizeof(struct rld_loaded_state) *
(rld_nallocated_states + NSTATES_INCREMENT) );
rld_nallocated_states += NSTATES_INCREMENT;
}
if(file_name == NULL){
for(i = 0; object_filenames[i] != NULL; )
i++;
rld_loaded_state[rld_nloaded_states].object_filenames =
allocate(i * sizeof(char *));
rld_loaded_state[rld_nloaded_states].nobject_filenames = i;
for(i = 0; object_filenames[i] != NULL; i++){
if(object_filenames[i][0] != '/'){
if(dir[0] == '\0'){
getwd(dir);
dir_len = strlen(dir);
}
rld_loaded_state[rld_nloaded_states].
object_filenames[i] =
allocate(dir_len + 1 +
strlen(object_filenames[i]) + 1);
strcpy(rld_loaded_state[rld_nloaded_states].
object_filenames[i], dir);
strcat(rld_loaded_state[rld_nloaded_states].
object_filenames[i], "/");
strcat(rld_loaded_state[rld_nloaded_states].
object_filenames[i], object_filenames[i]);
}
else{
rld_loaded_state[rld_nloaded_states].
object_filenames[i] =
allocate(strlen(object_filenames[i]) + 1);
strcpy(rld_loaded_state[rld_nloaded_states].
object_filenames[i], object_filenames[i]);
}
}
}
else{
rld_loaded_state[rld_nloaded_states].object_filenames =
allocate(sizeof(char *));
rld_loaded_state[rld_nloaded_states].nobject_filenames = 1;
rld_loaded_state[rld_nloaded_states].object_filenames[0] =
allocate(strlen(file_name) + 1);
strcpy(rld_loaded_state[rld_nloaded_states].
object_filenames[0], file_name);
}
rld_loaded_state[rld_nloaded_states].header_addr =
(struct mach_header *)output_addr;
rld_nloaded_states += 1;
rld_loaded_state_changed();
}
if(base_name == NULL){
if(rld_monaddition != NULL && rld_maintain_states == TRUE){
(*rld_monaddition)(output_addr, output_addr + output_size);
}
s = getsectbynamefromheader((struct mach_header *)output_addr,
"__TEXT", "__constructor");
if(s != NULL){
routines = (void(**)(void))s->addr;
n = s->size / sizeof(routines[0]);
for(i = 0; i < n; i++)
(*routines[i])();
}
s = getsectbynamefromheader((struct mach_header *)output_addr,
"__TEXT", "__destructor");
if(s != NULL){
routines = (void(**)(void))s->addr;
n = s->size / sizeof(routines[0]);
for(i = 0; i < n; i++)
atexit(routines[i]);
}
}
#endif
return(1);
}
#if !defined(SA_RLD)
#if defined(KLD)
#if !defined(__STATIC__)
long
kld_load_basefile(
const char *base_filename)
{
return(internal_kld_load_basefile(base_filename, NULL, 0));
}
#endif
long
kld_load_basefile_from_memory(
const char *base_filename,
char *base_addr,
long base_size)
{
return(internal_kld_load_basefile(base_filename, base_addr, base_size));
}
#else
long
rld_load_basefile(
NXStream *stream,
const char *base_filename)
{
return(internal_rld_load_basefile(stream, base_filename, NULL, 0));
}
#endif
static long
#ifdef KLD
internal_kld_load_basefile(
#else
internal_rld_load_basefile(
NXStream *stream,
#endif
const char *base_filename,
char *base_addr,
long base_size)
{
#if !(defined(KLD) && defined(__STATIC__))
unsigned long size;
char *addr;
int fd;
struct stat stat_buf;
kern_return_t r;
struct fat_header *fat_header;
#ifdef __LITTLE_ENDIAN__
struct fat_header struct_fat_header;
#endif
struct fat_arch *fat_archs, *best_fat_arch;
struct arch_flag host_arch_flag;
enum bool from_fat_file;
size = 0;
from_fat_file = FALSE;
#endif
#ifndef KLD
error_stream = stream;
#endif
if(fatals == 1){
print("previous fatal errors occured, can no longer succeed");
return(0);
}
if(setjmp(rld_env) != 0){
if(fatals == 0)
#ifdef KLD
kld_unload_all(1);
#else
rld_unload_all(stream, 1);
#endif
return(0);
}
errors = 0;
if(base_obj != NULL){
error("a base program is currently loaded");
return(0);
}
if(cur_set != -1){
error("object sets are currently loaded (base file must be loaded"
"before object sets)");
return(0);
}
#ifdef KLD
progname = "kld()";
#else
progname = "rld()";
#endif
host_pagesize = getpagesize();
host_byte_sex = get_host_byte_sex();
strip_base_symbols = TRUE;
force_cpusubtype_ALL = TRUE;
base_name = allocate(strlen(base_filename) + 1);
strcpy(base_name, base_filename);
#if !(defined(KLD) && defined(__STATIC__))
if (base_addr == NULL) {
if((fd = open(base_name, O_RDONLY, 0)) == -1){
system_error("Can't open: %s", base_name);
free(base_name);
base_name = NULL;
return(0);
}
if(fstat(fd, &stat_buf) == -1)
system_fatal("Can't stat file: %s", base_name);
if(stat_buf.st_size == 0){
error("file: %s is empty (not an object)", base_name);
close(fd);
free(base_name);
base_name = NULL;
return(0);
}
size = stat_buf.st_size;
if((r = map_fd((int)fd, (vm_offset_t)0, (vm_offset_t *)&addr,
(boolean_t)TRUE, (vm_size_t)size)) != KERN_SUCCESS)
mach_fatal(r, "can't map file: %s", base_name);
#ifdef RLD_VM_ALLOC_DEBUG
print("rld() map_fd: addr = 0x%0x size = 0x%x\n",
(unsigned int)addr, (unsigned int)size);
#endif
close(fd);
if(sizeof(struct fat_header) > size){
error("truncated or malformed file: %s (file size too small "
"to be any kind of object)", base_name);
free(base_name);
base_name = NULL;
return(0);
}
from_fat_file = FALSE;
fat_header = (struct fat_header *)addr;
#ifdef __LITTLE_ENDIAN__
fat_archs = NULL;
#endif
#ifdef __BIG_ENDIAN__
if(fat_header->magic == FAT_MAGIC)
#endif
#ifdef __LITTLE_ENDIAN__
if(fat_header->magic == SWAP_LONG(FAT_MAGIC))
#endif
{
from_fat_file = TRUE;
#ifdef __LITTLE_ENDIAN__
struct_fat_header = *fat_header;
swap_fat_header(&struct_fat_header, host_byte_sex);
fat_header = &struct_fat_header;
#endif
if(sizeof(struct fat_header) + fat_header->nfat_arch *
sizeof(struct fat_arch) > (unsigned long)size){
error("fat file: %s truncated or malformed (fat_arch "
"structs would extend past the end of the file)",
base_name);
goto rld_load_basefile_error_return;
}
#ifdef __BIG_ENDIAN__
fat_archs = (struct fat_arch *)
(addr + sizeof(struct fat_header));
#endif
#ifdef __LITTLE_ENDIAN__
fat_archs = allocate(fat_header->nfat_arch *
sizeof(struct fat_arch));
memcpy(fat_archs, addr + sizeof(struct fat_header),
fat_header->nfat_arch * sizeof(struct fat_arch));
swap_fat_arch(fat_archs, fat_header->nfat_arch, host_byte_sex);
#endif
check_fat(base_name, size, fat_header, fat_archs, NULL, 0);
if(errors){
goto rld_load_basefile_error_return;
return(0);
}
#if defined(KLD) && defined(__STATIC__)
best_fat_arch = cpusubtype_findbestarch(
arch_flag.cputype, arch_flag.cpusubtype,
fat_archs, fat_header->nfat_arch);
#else
if(get_arch_from_host(&host_arch_flag, NULL) == 0){
error("can't determine the host architecture (fix "
"get_arch_from_host() )");
goto rld_load_basefile_error_return;
}
best_fat_arch = cpusubtype_findbestarch(
host_arch_flag.cputype,
host_arch_flag.cpusubtype,
fat_archs, fat_header->nfat_arch);
#endif
if(best_fat_arch != NULL){
cur_obj = new_object_file();
cur_obj->file_name = base_name;
cur_obj->obj_addr = addr + best_fat_arch->offset;
cur_obj->obj_size = best_fat_arch->size;
cur_obj->from_fat_file = TRUE;
base_obj = cur_obj;
}
if(base_obj == NULL){
error("fat file: %s does not contain the host architecture "
"(can't be used as a base file)", base_name);
goto rld_load_basefile_error_return;
}
#ifdef __LITTLE_ENDIAN__
free(fat_archs);
#endif
}
else{
cur_obj = new_object_file();
cur_obj->file_name = base_name;
cur_obj->obj_addr = addr;
cur_obj->obj_size = size;
base_obj = cur_obj;
}
}
else
#endif
{
cur_obj = new_object_file();
cur_obj->file_name = base_name;
cur_obj->obj_addr = base_addr;
cur_obj->obj_size = base_size;
cur_obj->user_obj_addr = TRUE;
base_obj = cur_obj;
}
merge(FALSE, FALSE, FALSE);
if(errors){
#ifdef KLD
kld_unload_all(1);
#else
rld_unload_all(stream, 1);
#endif
return(0);
}
clean_objects();
clean_archives_and_fats();
#if !(defined(KLD) && defined(__STATIC__))
if(from_fat_file == TRUE){
if((r = vm_deallocate(mach_task_self(), (vm_address_t)addr,
(vm_size_t)size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() memory for mapped file %s",
base_name);
#ifdef RLD_VM_ALLOC_DEBUG
print("rld() vm_deallocate: addr = 0x%0x size = 0x%x\n",
(unsigned int)addr, (unsigned int)size);
#endif
}
rld_maintain_states = FALSE;
#endif
return(1);
#if !(defined(KLD) && defined(__STATIC__))
rld_load_basefile_error_return:
if((r = vm_deallocate(mach_task_self(), (vm_address_t)addr,
(vm_size_t)size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() memory for mapped file %s",
base_name);
#ifdef RLD_VM_ALLOC_DEBUG
print("rld() vm_deallocate: addr = 0x%0x size = 0x%x\n",
(unsigned int)addr, (unsigned int)size);
#endif
free(base_name);
base_name = NULL;
#ifdef __LITTLE_ENDIAN__
if(fat_archs != NULL)
free(fat_archs);
#endif
return(0);
#endif
}
#ifndef KLD
long
rld_unload(
NXStream *stream)
{
return(internal_rld_unload(stream, FALSE));
}
#endif
#endif
static
long
#ifdef KLD
internal_kld_unload(
#else
internal_rld_unload(
NXStream *stream,
#endif
enum bool internal_cleanup)
{
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
kern_return_t r;
unsigned long i;
#endif
#ifndef KLD
error_stream = stream;
#endif
if(fatals == 1){
print("previous fatal errors occured, can no longer succeed");
return(0);
}
if(setjmp(rld_env) != 0){
return(0);
}
#ifdef KLD
progname = "kld()";
#else
progname = "rld()";
#endif
host_byte_sex = get_host_byte_sex();
force_cpusubtype_ALL = TRUE;
errors = 0;
free_multiple_defs();
free_undefined_list();
if(cur_set == -1){
error("no object sets currently loaded");
return(0);
}
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
if(internal_cleanup == FALSE && rld_maintain_states == TRUE){
rld_nloaded_states -= 1;
for(i = 0;
i < rld_loaded_state[rld_nloaded_states].nobject_filenames;
i++){
free(rld_loaded_state[rld_nloaded_states].
object_filenames[i]);
}
free(rld_loaded_state[rld_nloaded_states].object_filenames);
rld_loaded_state[rld_nloaded_states].object_filenames = NULL;
rld_loaded_state[rld_nloaded_states].nobject_filenames = 0;
rld_loaded_state[rld_nloaded_states].header_addr = NULL;
}
#endif
remove_merged_symbols();
remove_merged_sections();
clean_objects();
clean_archives_and_fats();
remove_objects();
if(sets[cur_set].output_addr != NULL){
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
if((r = vm_deallocate(mach_task_self(),
(vm_address_t)sets[cur_set].output_addr,
sets[cur_set].output_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() memory for output");
#endif
#ifdef RLD_VM_ALLOC_DEBUG
print("rld() vm_deallocate: addr = 0x%0x size = 0x%x\n",
(unsigned int)sets[cur_set].output_addr,
(unsigned int)sets[cur_set].output_size);
#endif
sets[cur_set].output_addr = NULL;
}
remove_set();
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
if(rld_maintain_states == TRUE)
rld_loaded_state_changed();
#endif
return(1);
}
#ifndef SA_RLD
long
#ifdef KLD
kld_unload_all(
#else
rld_unload_all(
NXStream *stream,
#endif
long deallocate_sets)
{
#if !(defined(KLD) && defined(__STATIC__))
kern_return_t r;
#endif
#ifndef KLD
unsigned long i, j, n;
#endif
#ifndef KLD
error_stream = stream;
#endif
if(fatals == 1){
print("previous fatal errors occured, can no longer succeed");
return(0);
}
if(setjmp(rld_env) != 0){
return(0);
}
#ifdef KLD
progname = "kld()";
#else
progname = "rld()";
#endif
host_byte_sex = get_host_byte_sex();
force_cpusubtype_ALL = TRUE;
errors = 0;
free_multiple_defs();
free_undefined_list();
if(cur_set == -1 && base_obj == NULL){
error("no object sets or base program currently loaded");
return(0);
}
#ifndef KLD
if(rld_maintain_states == TRUE){
n = rld_nloaded_states;
rld_nloaded_states = 0;
for(i = 0; i < n; i++){
for(j = 0; j < rld_loaded_state[i].nobject_filenames; j++)
free(rld_loaded_state[i].object_filenames[j]);
free(rld_loaded_state[i].object_filenames);
rld_loaded_state[i].object_filenames = NULL;
rld_loaded_state[i].nobject_filenames = 0;
rld_loaded_state[i].header_addr = NULL;
}
free(rld_loaded_state);
rld_loaded_state = NULL;
rld_nallocated_states = 0;
}
#endif
while(cur_set != -1){
remove_merged_symbols();
remove_merged_sections();
clean_objects();
clean_archives_and_fats();
remove_objects();
#if !(defined(KLD) && defined(__STATIC__))
if(deallocate_sets && sets[cur_set].output_addr != NULL){
if((r = vm_deallocate(mach_task_self(),
(vm_address_t)sets[cur_set].output_addr,
sets[cur_set].output_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() memory for output");
#ifdef RLD_VM_ALLOC_DEBUG
print("rld() vm_deallocate: addr = 0x%0x size = 0x%x\n",
(unsigned int)sets[cur_set].output_addr,
(unsigned int)sets[cur_set].output_size);
#endif
}
#endif
sets[cur_set].output_addr = NULL;
remove_set();
}
remove_merged_symbols();
remove_merged_sections();
if(base_name != NULL){
clean_objects();
clean_archives_and_fats();
free(base_name);
base_name = NULL;
}
remove_objects();
free_sets();
base_obj = NULL;
#ifndef KLD
if(rld_maintain_states == TRUE)
rld_loaded_state_changed();
rld_maintain_states = FALSE;
if(zonep != NULL)
NXDestroyZone(zonep);
zonep = NULL;
#endif
target_byte_sex = UNKNOWN_BYTE_SEX;
return(1);
}
#endif
#ifndef SA_RLD
long
#ifdef KLD
kld_lookup(
#else
rld_lookup(
NXStream *stream,
#endif
const char *symbol_name,
unsigned long *value)
{
struct merged_symbol *merged_symbol;
#ifndef KLD
error_stream = stream;
#endif
if(fatals == 1){
print("previous fatal errors occured, can no longer succeed");
return(0);
}
errors = 0;
merged_symbol = lookup_symbol((char *)symbol_name);
if(merged_symbol->name_len != 0){
if(value != NULL)
*value = merged_symbol->nlist.n_value;
return(1);
}
else{
if(value != NULL)
*value = 0;
return(0);
}
}
long
#ifdef KLD
kld_forget_symbol(
#else
rld_forget_symbol(
NXStream *stream,
#endif
const char *symbol_name)
{
struct merged_symbol *merged_symbol;
#ifndef KLD
error_stream = stream;
#endif
if(fatals == 1){
print("previous fatal errors occured, can no longer succeed");
return(0);
}
errors = 0;
merged_symbol = lookup_symbol((char *)symbol_name);
if(merged_symbol->name_len != 0){
merged_symbol->nlist.n_un.n_name[0] = '\0';
return(1);
}
else{
return(0);
}
}
#ifndef KLD
long
rld_write_symfile(
NXStream *stream,
const char *output_filename)
{
int fd;
long symbol_size, return_value;
kern_return_t r;
return_value = 1;
error_stream = stream;
if(fatals == 1){
print("previous fatal errors occured, can no longer succeed");
return(0);
}
if(setjmp(rld_env) != 0){
return(0);
}
#ifdef KLD
progname = "kld()";
#else
progname = "rld()";
#endif
host_byte_sex = get_host_byte_sex();
force_cpusubtype_ALL = TRUE;
errors = 0;
if(cur_set < 0){
error("no object sets currently loaded");
return(0);
}
layout_rld_symfile();
if(errors){
return_value = 0;
goto deallocate_and_return;
}
pass2_rld_symfile();
if(errors){
return_value = 0;
goto deallocate_and_return;
}
symbol_size = output_symtab_info.symtab_command.nsyms *
sizeof(struct nlist) +
output_symtab_info.symtab_command.strsize;
(void)unlink(output_filename);
if((fd = open(output_filename, O_WRONLY | O_CREAT | O_TRUNC,
0666)) == -1){
system_error("can't create output file: %s", output_filename);
return_value = 0;
goto deallocate_and_return;
}
else {
if(write(fd, output_addr, output_size + symbol_size) !=
(int)(output_size + symbol_size)){
system_error("can't write output file: %s",output_filename);
(void)unlink(output_filename);
return_value = 0;
goto deallocate_and_return;
}
if(close(fd) == -1){
system_error("can't close output file: %s",output_filename);
(void)unlink(output_filename);
return_value = 0;
goto deallocate_and_return;
}
}
deallocate_and_return:
if((r = vm_deallocate(mach_task_self(), (vm_address_t)(output_addr),
output_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() buffer for output "
"file's symbol table");
#ifdef RLD_VM_ALLOC_DEBUG
print("rld() vm_deallocate: addr = 0x%0x size = 0x%x\n",
(unsigned int)(output_addr), output_size);
rnd(output_size, host_pagesize)),
(unsigned int)deallocate_size);
#endif
return(return_value);
}
#endif
#if !(defined(KLD) && defined(__STATIC__))
static
void
rld_loaded_state_changed(
void)
{
#ifdef RLD_TEST
unsigned long i, j;
if(rld_maintain_states == TRUE)
print("rld_maintain_states = TRUE\n");
else
print("rld_maintain_states = FALSE\n");
print("rld_nloaded_states = %lu\n", rld_nloaded_states);
print("rld_loaded_state 0x%x\n", (unsigned int)rld_loaded_state);
for(i = 0; i < rld_nloaded_states; i++){
print("state %lu\n\tnobject_filenames %lu\n\tobject_filenames 0x%x"
"\n\theader_addr 0x%x\n", i,
rld_loaded_state[i].nobject_filenames,
(unsigned int)(rld_loaded_state[i].object_filenames),
(unsigned int)(rld_loaded_state[i].header_addr));
for(j = 0; j < rld_loaded_state[i].nobject_filenames; j++)
print("\t\t%s\n", rld_loaded_state[i].object_filenames[j]);
}
#endif
}
#endif
#ifndef KLD
static
void
rld_get_loaded_state(
struct rld_loaded_state **s,
unsigned long *n)
{
*s = rld_loaded_state;
*n = rld_nloaded_states;
}
void (*
moninitrld(
void (*m)(char *lowpc, char *highpc))
)(struct rld_loaded_state **s, unsigned long *n)
{
rld_monaddition = m;
return(rld_get_loaded_state);
}
char *
rld_get_current_header(
void)
{
if(cur_set == -1)
return(NULL);
else
return(sets[cur_set].output_addr);
}
#endif
void
#ifdef KLD
kld_address_func(
#else
rld_address_func(
#endif
unsigned long (*func)(unsigned long size, unsigned long headers_size))
{
address_func = func;
}
void
#ifdef KLD
kld_set_link_options(
#else
rld_set_link_options(
#endif
unsigned long link_options)
{
#ifdef KLD
if(KLD_STRIP_NONE & link_options)
kld_requested_strip_level = STRIP_NONE;
else
#endif
kld_requested_strip_level = STRIP_ALL;
}
#endif
__private_extern__
void
cleanup(void)
{
fatals = 1;
longjmp(rld_env, 1);
}
#if !defined(SA_RLD) && !defined(KLD)
__private_extern__
void
vprint(
const char *format,
va_list ap)
{
if(error_stream != NULL)
NXVPrintf(error_stream, format, ap);
NXVPrintf(error_stream, format, ap);
}
#endif
#ifdef KLD
__private_extern__
void
vprint(
const char *format,
va_list ap)
{
kld_error_vprintf(format, ap);
}
#endif
#if !defined(SA_RLD) && !defined(KLD)
__private_extern__
void *
allocate(
unsigned long size)
{
void *p;
if(zonep == NULL){
zonep = NXCreateZone(vm_page_size, vm_page_size, 1);
if(zonep == NULL)
fatal("can't create NXZone");
NXNameZone(zonep, "rld");
}
if(size == 0)
return(NULL);
if((p = NXZoneMalloc(zonep, size)) == NULL)
system_fatal("virtual memory exhausted (NXZoneMalloc failed)");
return(p);
}
__private_extern__
void *
reallocate(
void *p,
unsigned long size)
{
if(zonep == NULL){
zonep = NXCreateZone(vm_page_size, vm_page_size, 1);
if(zonep == NULL)
fatal("can't create NXZone");
NXNameZone(zonep, "rld");
}
if(p == NULL)
return(allocate(size));
if((p = NXZoneRealloc(zonep, p, size)) == NULL)
system_fatal("virtual memory exhausted (NXZoneRealloc failed)");
return(p);
}
#endif
#ifdef SA_RLD
__private_extern__ char *sa_rld_output_addr = NULL;
__private_extern__ unsigned long sa_rld_output_size = 0;
static char *sa_rld_error_buf_addr = NULL;
static unsigned long sa_rld_error_buf_size = 0;
static enum bool sa_rld_malloc_initialized = FALSE;
static
int
sa_rld_internal(
char *basefile_name,
struct mach_header *basefile_addr,
char *object_name,
char *object_addr,
unsigned long object_size,
char *workmem_addr,
unsigned long *workmem_size,
char *error_buf_addr,
unsigned long error_buf_size,
char *malloc_addr,
unsigned long malloc_len,
struct nlist *symtab,
unsigned long nsyms,
char *strtab,
unsigned long strsize)
{
int status;
struct segment_command *linkedit;
if(sa_rld_malloc_initialized == FALSE){
malloc_init(malloc_addr, malloc_len, 1000);
sa_rld_malloc_initialized = TRUE;
}
if(setjmp(rld_env) != 0){
if(fatals == 0)
rld_unload_all(NULL, 1);
return(0);
}
errors = 0;
#ifdef KLD
progname = "kld()";
#else
progname = "rld()";
#endif
host_pagesize = getpagesize();
host_byte_sex = get_host_byte_sex();
strip_base_symbols = TRUE;
force_cpusubtype_ALL = TRUE;
sa_rld_output_size = *workmem_size;
sa_rld_output_addr = workmem_addr;
sa_rld_error_buf_addr = error_buf_addr;
sa_rld_error_buf_size = error_buf_size;
if(base_obj == NULL){
if(symtab == NULL){
linkedit = getsegbynamefromheader(basefile_addr, SEG_LINKEDIT);
if(linkedit != NULL)
merge_base_program(basefile_name, basefile_addr, linkedit,
NULL, 0, NULL, 0);
}
else{
merge_base_program(basefile_name, basefile_addr, NULL,
symtab, nsyms, strtab, strsize);
}
if (target_byte_sex == UNKNOWN_BYTE_SEX)
target_byte_sex = host_byte_sex;
if(errors){
fatals = 1;
return(0);
}
}
status = internal_rld_load(NULL,
NULL,
NULL,
NULL,
object_name, object_addr, object_size);
if(status == 0)
return(0);
status = internal_rld_unload(NULL, FALSE);
*workmem_size = output_size;
return(status);
}
int
sa_rld(
char *basefile_name,
struct mach_header *basefile_addr,
char *object_name,
char *object_addr,
unsigned long object_size,
char *workmem_addr,
unsigned long *workmem_size,
char *error_buf_addr,
unsigned long error_buf_size,
char *malloc_addr,
unsigned long malloc_len)
{
return(sa_rld_internal(basefile_name, basefile_addr, object_name,
object_addr, object_size, workmem_addr,
workmem_size, error_buf_addr, error_buf_size,
malloc_addr, malloc_len, NULL, 0, NULL, 0));
}
int
sa_rld_with_symtab(
char *basefile_name,
struct mach_header *basefile_addr,
char *object_name,
char *object_addr,
unsigned long object_size,
char *workmem_addr,
unsigned long *workmem_size,
char *error_buf_addr,
unsigned long error_buf_size,
char *malloc_addr,
unsigned long malloc_len,
struct nlist *symtab,
unsigned long nsyms,
char *strtab,
unsigned long strsize)
{
return(sa_rld_internal(basefile_name, basefile_addr, object_name,
object_addr, object_size, workmem_addr,
workmem_size, error_buf_addr, error_buf_size,
malloc_addr, malloc_len, symtab, nsyms, strtab,
strsize));
}
__private_extern__
void
vprint(
const char *format,
va_list ap)
{
unsigned long new;
new = slvprintf(sa_rld_error_buf_addr,
sa_rld_error_buf_size, format, ap);
sa_rld_error_buf_addr += new;
sa_rld_error_buf_size -= new;
}
#endif
#if defined(SA_RLD) || defined(KLD)
__private_extern__
void *
allocate(
unsigned long size)
{
void *p;
if(size == 0)
return(NULL);
if((p = malloc(size)) == NULL)
fatal("virtual memory exhausted (malloc failed)");
return(p);
}
__private_extern__
void *
reallocate(
void *p,
unsigned long size)
{
if(p == NULL)
return(allocate(size));
if((p = realloc(p, size)) == NULL)
fatal("virtual memory exhausted (realloc failed)");
return(p);
}
#endif
__private_extern__
char *
savestr(
const char *s)
{
long len;
char *r;
len = strlen(s) + 1;
r = (char *)allocate(len);
strcpy(r, s);
return(r);
}
#if defined(KLD) && defined(__STATIC__)
__private_extern__
struct mach_header *
_NSGetMachExecuteHeader(void)
{
return((struct mach_header *)&_mh_execute_header);
}
#endif
#endif