#ifdef SHLIB
#include "shlib.h"
#endif
#ifndef RLD
#include <stdio.h>
#include <stdarg.h>
#include <strings.h>
#include <mach/mach.h>
#include <mach-o/loader.h>
#include <ar.h>
#include "stuff/bool.h"
#include "stuff/bytesex.h"
#include "ld.h"
#include "live_refs.h"
#include "objects.h"
#include "sections.h"
#include "fvmlibs.h"
__private_extern__ struct merged_fvmlib *merged_fvmlibs = NULL;
__private_extern__ struct merged_segment *fvmlib_segments = NULL;
static struct merged_fvmlib *lookup_merged_fvmlib(struct fvmlib_command *fl);
static void add_fvmlib_segment(struct segment_command *sg, char *fvmlib_name);
__private_extern__
void
merge_fvmlibs(void)
{
unsigned long i, nload_fvmlibs, nid_fvmlibs, nfvmlib_segments;
struct mach_header *mh;
struct load_command *lc;
struct segment_command *sg;
struct fvmlib_command *fl;
struct merged_fvmlib *mfl;
#ifdef DEBUG
fl = NULL;;
mfl = NULL;;
#endif
nload_fvmlibs = 0;
nid_fvmlibs = 0;
nfvmlib_segments = 0;
mh = (struct mach_header *)cur_obj->obj_addr;
lc = (struct load_command *)((char *)cur_obj->obj_addr +
sizeof(struct mach_header));
for(i = 0; i < mh->ncmds; i++){
if(lc->cmd == LC_LOADFVMLIB){
fl = (struct fvmlib_command *)lc;
mfl = lookup_merged_fvmlib(fl);
nload_fvmlibs++;
}
if(lc->cmd == LC_IDFVMLIB){
fl = (struct fvmlib_command *)lc;
mfl = lookup_merged_fvmlib(fl);
nid_fvmlibs++;
}
else if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(sg->flags == SG_FVMLIB)
nfvmlib_segments++;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(filetype == MH_FVMLIB){
if(nid_fvmlibs > 1){
error_with_cur_obj("contains more than one LC_IDFVMLIB load "
"command");
return;
}
}
else{
if(nfvmlib_segments == 0)
return;
if(nload_fvmlibs == 0){
error_with_cur_obj("contains SG_FVMLIB segments but no "
"LC_LOADFVMLIB load command");
return;
}
if(nload_fvmlibs > 1){
error_with_cur_obj("contains SG_FVMLIB segments and more than "
"one LC_LOADFVMLIB load command");
return;
}
if(mfl->multiple)
return;
lc = (struct load_command *)((char *)cur_obj->obj_addr +
sizeof(struct mach_header));
for(i = 0; i < mh->ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(sg->flags == SG_FVMLIB)
add_fvmlib_segment(sg,
(char *)fl + fl->fvmlib.name.offset);
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
}
static
struct merged_fvmlib *
lookup_merged_fvmlib(
struct fvmlib_command *fl)
{
char *fvmlib_name;
struct merged_fvmlib **p, *mfl;
fvmlib_name = (char *)fl + fl->fvmlib.name.offset;
p = &merged_fvmlibs;
while(*p){
mfl = *p;
if(strcmp(mfl->fvmlib_name, fvmlib_name) == 0){
if(mfl->multiple == FALSE){
if(mfl->fl->cmd == LC_IDFVMLIB)
error("multiple object files identify fixed VM library "
"%s", fvmlib_name);
else
warning("multiple object files load fixed VM library "
"%s", fvmlib_name);
print_obj_name(mfl->definition_object);
print("%s fixed VM library %s\n",
mfl->fl->cmd == LC_LOADFVMLIB ? "loads" :"identifies",
fvmlib_name);
mfl->multiple = TRUE;
}
print_obj_name(cur_obj);
print("%s fixed VM library %s\n",
mfl->fl->cmd == LC_LOADFVMLIB ? "loads" : "identifies",
fvmlib_name);
return(mfl);
}
p = &(mfl->next);
}
*p = allocate(sizeof(struct merged_fvmlib));
memset(*p, '\0', sizeof(struct merged_fvmlib));
mfl = *p;
mfl->fl = fl;
mfl->fvmlib_name = fvmlib_name;
mfl->definition_object = cur_obj;
mfl->multiple = FALSE;
return(mfl);
}
static
void
add_fvmlib_segment(
struct segment_command *sg,
char *fvmlib_name)
{
struct merged_segment **p, *msg;
p = &fvmlib_segments;
while(*p){
msg = *p;
p = &(msg->next);
}
*p = allocate(sizeof(struct merged_segment));
msg = *p;
memset(msg, '\0', sizeof(struct merged_segment));
msg->sg = *sg;
msg->filename = fvmlib_name;
}
#ifdef DEBUG
__private_extern__
void
print_load_fvmlibs_list(void)
{
struct merged_fvmlib **p, *mfl;
print("Load fvmlibs list\n");
p = &merged_fvmlibs;
while(*p){
mfl = *p;
if(mfl->fl->cmd == LC_LOADFVMLIB)
print(" LC_LOADFVMLIB\n");
else
print(" LC_IDFVMLIB\n");
print("\tcmdsize %u\n", mfl->fl->cmdsize);
if(mfl->fl->fvmlib.name.offset < mfl->fl->cmdsize)
print("\tname %s (offset %u)\n",
(char *)(mfl->fl) + mfl->fl->fvmlib.name.offset,
mfl->fl->fvmlib.name.offset);
else
print("\tname ?(bad offset %u)\n",mfl->fl->fvmlib.name.offset);
print("\tminor version %u\n", mfl->fl->fvmlib.minor_version);
print("\theader addr 0x%08x\n",
(unsigned int)(mfl->fl->fvmlib.header_addr));
print(" fvmlib_name %s\n", mfl->fvmlib_name);
print(" definition_object ");
print_obj_name(mfl->definition_object);
print("\n");
print(" multiple %s\n", mfl->multiple == TRUE ? "TRUE" :
"FALSE");
p = &(mfl->next);
}
}
__private_extern__
void
print_fvmlib_segments(void)
{
struct merged_segment **p, *msg;
unsigned long flags;
print("FVMLIB segments\n");
p = &fvmlib_segments;
while(*p){
msg = *p;
print(" filename %s\n", msg->filename);
print("\t cmd LC_SEGMENT\n");
print("\t cmdsize %u\n", msg->sg.cmdsize);
print("\t segname %.16s\n", msg->sg.segname);
print("\t vmaddr 0x%08x\n", (unsigned int)(msg->sg.vmaddr));
print("\t vmsize 0x%08x\n", (unsigned int)(msg->sg.vmsize));
print("\t fileoff %u\n", msg->sg.fileoff);
print("\t filesize %u\n", msg->sg.filesize);
print("\t maxprot 0x%08x\n", (unsigned int)(msg->sg.maxprot));
print("\t initprot 0x%08x\n", (unsigned int)(msg->sg.initprot));
print("\t nsects %u\n", msg->sg.nsects);
print("\t flags");
if(msg->sg.flags == 0)
print(" (none)\n");
else{
flags = msg->sg.flags;
if(flags & SG_HIGHVM){
print(" HIGHVM");
flags &= ~SG_HIGHVM;
}
if(flags & SG_FVMLIB){
print(" FVMLIB");
flags &= ~SG_FVMLIB;
}
if(flags & SG_NORELOC){
print(" NORELOC");
flags &= ~SG_NORELOC;
}
if(flags)
print(" 0x%x (unknown flags)\n", (unsigned int)flags);
else
print("\n");
}
p = &(msg->next);
}
}
#endif
#endif