#undef HOST_DEBUG
#include <stdlib.h>
#include <stdio.h>
#include <sys/file.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#include <mach-o/ranlib.h>
#include <ar.h>
#include <ctype.h>
#include <strings.h>
#include <mach/mach.h>
#include "stuff/openstep_mach.h"
#include <libc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "stuff/ofile.h"
#include "stuff/errors.h"
#include "stuff/allocate.h"
#include "stuff/hash_string.h"
#include "libgcc.h"
#include "mkshlib.h"
extern char *mktemp();
#define FILEDEF_NAME ".file_definition_"
#define N_PRIVATE_UNDF 0xff
struct ext {
char *name;
long value;
struct branch *bp;
long branch_value;
struct object *op;
struct ext *alias;
long private;
struct ext *next;
};
#define EXT_HASH_SIZE 251
struct ext *ext_hash[EXT_HASH_SIZE];
struct ref {
char *name;
struct ref *next;
};
static struct mach_header target_mh;
static struct load_command *load_commands;
static struct lib_object {
long object_size;
long nfvmsegs;
long fvmlib_name_size;
long string_size;
} lib_object = { 0 };
static struct ref_object {
unsigned long object_size;
unsigned long string_size;
} ref_object = { 0 };
static struct toc_object {
unsigned long object_size;
unsigned long nranlibs;
struct ranlib *ranlibs;
unsigned long ranlib_string_size;
char *ranlib_strings;
} toc_object = { 0 };
static long host_lib_size = 0;
static void make_exthash(
void);
static void scan_objects(
void);
static void scan_objects_processor(
struct ofile *ofile,
char *arch_name,
void *cookie);
static void make_references(
void);
static void build_archive(
void);
static int ranlib_qsort(
const struct ranlib *ran1,
const struct ranlib *ran2);
static void build_lib_object(
void);
static void build_ref_object(
void);
static void build_host_objects(
void);
static void init_symbol(
struct object *op,
char *name,
struct relocation_info *reloc,
long *value,
long *defined,
long symbolnum,
long address);
static void write_archive(
void);
static void write_lib_obj(
char *buffer);
static void write_ref_obj(
char *buffer);
static void write_object(
struct object *op,
char *buffer);
void
host()
{
make_exthash();
scan_objects();
make_references();
build_archive();
write_archive();
}
static
void
make_exthash(void)
{
struct ofile ofile;
unsigned int string_size, hash_key, i, nsyms;
struct nlist *symbols;
char *strings, *p;
struct ext *extp, *bextp;
struct branch *bp;
struct alias *ap;
struct load_command *lc;
struct symtab_command *st;
struct oddball *obp;
if(ofile_map(target_filename, NULL, NULL, &ofile, FALSE) == FALSE)
exit(1);
if(ofile.file_type != OFILE_Mach_O || ofile.mh->filetype != MH_FVMLIB)
fatal("file: %s is not a target shared library", target_name);
target_mh = *(ofile.mh);
load_commands = ofile.load_commands;
lc = ofile.load_commands;
st = (struct symtab_command *)0;
for(i = 0; i < ofile.mh->ncmds; i++){
switch(lc->cmd){
case LC_SYMTAB:
if(st != (struct symtab_command *)0)
fatal("More than one symtab_command in: %s", target_name);
else
st = (struct symtab_command *)lc;
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(st == (struct symtab_command *)0)
fatal("No symtab_command in: %s", target_name);
if(st->nsyms == 0)
fatal("No symbol table in: %s", target_name);
if(st->strsize == 0)
fatal("No string table in: %s", target_name);
symbols = (struct nlist *)(ofile.object_addr + st->symoff);
nsyms = st->nsyms;
if(ofile.object_byte_sex != host_byte_sex)
swap_nlist(symbols, nsyms, host_byte_sex);
strings = (char *)(ofile.object_addr + st->stroff);
string_size = st->strsize;
for(i = 0; i < nsyms; i++){
if((symbols[i].n_type & N_EXT) == 0)
continue;
if(symbols[i].n_un.n_strx < 0 ||
(unsigned long)symbols[i].n_un.n_strx > string_size)
fatal("bad string index for symbol %d in target shared "
"library: %s", i, target_filename);
symbols[i].n_un.n_name = strings + symbols[i].n_un.n_strx;
hash_key = hash_string(symbols[i].n_un.n_name) % EXT_HASH_SIZE;
extp = ext_hash[hash_key];
while(extp != (struct ext *)0){
if(strcmp(symbols[i].n_un.n_name, extp->name) == 0)
fatal("symbol %s appears more than once in target shared "
"library: %s", extp->name, target_filename);
extp = extp->next;
}
extp = allocate(sizeof(struct ext));
extp->name = savestr(symbols[i].n_un.n_name);
extp->value = symbols[i].n_value;
extp->bp = (struct branch *)0;
extp->branch_value = BAD_ADDRESS;
extp->op = (struct object *)0;
extp->alias = (struct ext *)0;
extp->private = 0;
extp->next = ext_hash[hash_key];
ext_hash[hash_key] = extp;
if(is_branch_slot_symbol(extp->name))
continue;
if(is_libdef_symbol(extp->name))
continue;
hash_key = hash_string(extp->name) % BRANCH_HASH_SIZE;
bp = branch_hash[hash_key];
while(bp != (struct branch *)0){
if(strcmp(bp->name, extp->name) == 0)
break;
bp = bp->next;
}
extp->bp = bp;
hash_key = hash_string(extp->name) % ODDBALL_HASH_SIZE;
obp = oddball_hash[hash_key];
while(obp != (struct oddball *)0){
if(strcmp(obp->name, extp->name) == 0)
break;
obp = obp->next;
}
if(obp != (struct oddball *)0 && obp->private)
extp->private = 1;
if((symbols[i].n_type & N_TYPE) == N_SECT &&
symbols[i].n_sect == 1){
if(extp->bp == (struct branch *)0 &&
(obp == (struct oddball *)0 ||
(obp != (struct oddball *)0 &&
(obp->private == 0 && obp->nobranch == 0)) ) )
error("external text symbol: %s does not have an entry in "
"the branch table", extp->name);
}
else{
if(extp->bp != (struct branch *)0)
error("non external text symbol: %s has an entry in "
"the branch table", extp->name);
}
}
ap = aliases;
while(ap != (struct alias *)0){
hash_key = hash_string(ap->alias_name) % EXT_HASH_SIZE;
extp = ext_hash[hash_key];
while(extp != (struct ext *)0){
if(strcmp(ap->alias_name, extp->name) == 0)
break;
extp = extp->next;
}
if(extp == (struct ext *)0)
fatal("aliased symbol %s does not appears (that should) in "
"target shared library: %s", extp->name, target_filename);
hash_key = hash_string(ap->real_name) % EXT_HASH_SIZE;
extp->alias = ext_hash[hash_key];
while(extp->alias != (struct ext *)0){
if(strcmp(ap->real_name, extp->alias->name) == 0)
break;
extp->alias = extp->alias->next;
}
if(extp->alias == (struct ext *)0)
fatal("real symbol %s for aliased symbol %s not found in "
"target shared library\n", ap->real_name,
extp->alias->name);
ap = ap->next;
}
for(i = 0; i < EXT_HASH_SIZE; i++){
extp = ext_hash[i];
while(extp != (struct ext *)0){
if(extp->bp != (struct branch *)0){
p = branch_slot_symbol(extp->bp->max_slotnum);
hash_key = hash_string(p) % EXT_HASH_SIZE;
bextp = ext_hash[hash_key];
while(bextp != (struct ext *)0){
if(strcmp(p, bextp->name) == 0)
break;
bextp = bextp->next;
}
if(bextp == (struct ext *)0)
fatal("branch table symbol for: %s not found in target "
"shared library: %s", extp->name,target_filename);
extp->branch_value = bextp->value;
}
extp = extp->next;
}
}
#ifdef HOST_DEBUG
printf("Just after building external symbol table\n");
for(i = 0; i < EXT_HASH_SIZE; i++){
extp = ext_hash[i];
while(extp != (struct ext *)0){
printf("\textp = 0x%x { %s, 0x%x, 0x%x, 0x%x, 0x%x }\n", extp,
extp->name, extp->value, extp->bp, extp->branch_value,
extp->next);
if(extp->bp != (struct branch *)0)
printf("\t\tbp = 0x%x { %s, %d, 0x%x }\n", extp->bp,
extp->bp->name, extp->bp->max_slotnum,
extp->bp->next);
extp = extp->next;
}
}
#endif
}
static
void
scan_objects(void)
{
unsigned long i;
for(i = 0; i < nobject_list; i++){
ofile_process(object_list[i]->name, &arch_flag, 1, FALSE, FALSE,
TRUE, FALSE, scan_objects_processor, (void *)&i);
}
}
static
void
scan_objects_processor(
struct ofile *ofile,
char *arch_name,
void *cookie)
{
unsigned long i, j, k, l, nsyms, string_size, hash_key;
struct load_command *lc;
struct symtab_command *st;
struct nlist *symbols;
char *strings, *p, *q;
struct ext *extp;
i = *((long *)cookie);
st = NULL;
lc = ofile->load_commands;
for(j = 0; j < ofile->mh->ncmds; j++){
if(lc->cmd == LC_SYMTAB){
if(st != NULL)
fatal("more than one symtab command in object file: %s",
ofile->file_name);
st = (struct symtab_command *)lc;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(st == NULL)
return;
object_list[i]->nsymbols = 0;
object_list[i]->string_size = 1;
if(st->nsyms == 0){
return;
}
symbols = (struct nlist *)(ofile->object_addr + st->symoff);
nsyms = st->nsyms;
if(ofile->object_byte_sex != host_byte_sex)
swap_nlist(symbols, nsyms, host_byte_sex);
strings = ofile->object_addr + st->stroff;
string_size = st->strsize;
for(j = 0; j < nsyms; j++){
if((symbols[j].n_type & N_EXT) == 0)
continue;
if(symbols[j].n_un.n_strx < 0 ||
(unsigned long)symbols[j].n_un.n_strx > string_size)
fatal("bad string index for symbol %ld in object file: %s ",
j, ofile->file_name);
symbols[j].n_un.n_name = strings + symbols[j].n_un.n_strx;
p = symbols[j].n_un.n_name;
hash_key = hash_string(p) % EXT_HASH_SIZE;
extp = ext_hash[hash_key];
while(extp != (struct ext *)0){
if(strcmp(p, extp->name) == 0)
break;
extp = extp->next;
}
if(extp == (struct ext *)0)
fatal("symbol: %s in object: %s not found in target "
"shared library: %s", p, ofile->file_name,
target_filename);
if(extp->alias != (struct ext *)0){
symbols[j].n_un.n_name = extp->alias->name;
}
else{
if((symbols[j].n_type & N_TYPE) != N_UNDF){
if(extp->op != (struct object *)0)
fatal("symbol: %s defined in both: %s and %s", p,
ofile->file_name, extp->op->name);
extp->op = object_list[i];
}
}
if(extp->private ||
(extp->alias != (struct ext *)0 && extp->alias->private) ){
if(symbols[j].n_type == (N_UNDF|N_EXT)){
object_list[i]->pu_nsymbols++;
object_list[i]->pu_string_size +=
strlen(symbols[j].n_un.n_name) + 1;
symbols[j].n_type = N_PRIVATE_UNDF;
}
else{
symbols[j].n_type &= ~N_EXT;
}
continue;
}
object_list[i]->nsymbols++;
object_list[i]->string_size +=
strlen(symbols[j].n_un.n_name) + 1;
}
object_list[i]->symbols = allocate(object_list[i]->nsymbols *
sizeof(struct nlist));
object_list[i]->strings = allocate(object_list[i]->string_size);
object_list[i]->pu_symbols = allocate(object_list[i]->pu_nsymbols *
sizeof(struct nlist));
object_list[i]->pu_strings =
allocate(object_list[i]->pu_string_size);
k = 0;
p = object_list[i]->strings;
*p++ = '\0';
l = 0;
q = object_list[i]->pu_strings;
for(j = 0; j < nsyms; j++){
if(symbols[j].n_type == N_PRIVATE_UNDF){
object_list[i]->pu_symbols[l] = symbols[j];
strcpy(q, symbols[j].n_un.n_name);
object_list[i]->pu_symbols[l].n_un.n_name = q;
l++;
q += strlen(symbols[j].n_un.n_name) + 1;
continue;
}
if((symbols[j].n_type & N_EXT) == 0)
continue;
object_list[i]->symbols[k] = symbols[j];
strcpy(p, symbols[j].n_un.n_name);
object_list[i]->symbols[k].n_un.n_name = p;
k++;
p += strlen(symbols[j].n_un.n_name) + 1;
}
#ifdef HOST_DEBUG
printf("Symbol tables of host objects\n");
for(i = 0; i < nobject_list; i++){
printf("\tobject = %s\n", ofile->file_name);
for(j = 0;
j < object_list[i]->nsymbols;
j++){
printf("\t\tsymbol = %s value = 0x%x\n",
object_list[i]->symbols[j].n_un.n_name,
object_list[i]->symbols[j].n_value);
}
for(j = 0;
j < object_list[i]->pu_nsymbols;
j++){
printf("\t\tprivate undefined = %s value = 0x%x\n",
object_list[i]->pu_symbols[j].n_un.n_name,
object_list[i]->pu_symbols[j].n_value);
}
}
#endif
}
static
void
make_references(void)
{
unsigned long i, j, hash_key;
struct ext *extp;
struct ref *refp;
char *p;
#ifdef HOST_DEBUG
printf("External symbol table with defining references\n");
for(i = 0; i < nobject_list; i++){
extp = ext_hash[i];
while(extp != (struct ext *)0){
if(extp->op != (struct object *)0)
printf("\text = %s defined in %s\n",
extp->name, extp->op->name);
else
printf("\text = %s not defined in any object\n",
extp->name);
extp = extp->next;
}
}
#endif
for(i = 0; i < nobject_list; i++){
object_list[i]->filedef_name =
makestr(FILEDEF_NAME, target_base_name, "_",
object_list[i]->base_name, (char *)0);
}
for(i = 0; i < nobject_list; i++){
for(j = 0;
j < object_list[i]->nsymbols;
j++){
if((object_list[i]->symbols[j].n_type & N_TYPE) == N_UNDF){
p = object_list[i]->symbols[j].n_un.n_name;
hash_key = hash_string(p) % EXT_HASH_SIZE;
extp = ext_hash[hash_key];
while(extp != (struct ext *)0){
if(strcmp(p, extp->name) == 0)
break;
extp = extp->next;
}
if(extp == (struct ext *)0)
fatal("symbol: %s in object: %s not found in target "
"shared library: %s", p, object_list[i]->name,
target_filename);
if(extp->alias != (struct ext *)0)
extp = extp->alias;
if(extp->op != (struct object *)0){
refp = object_list[i]->refs;
while(refp != (struct ref *)0){
if(strcmp(refp->name, extp->op->filedef_name) == 0)
break;
refp = refp->next;
}
if(refp == (struct ref *)0){
refp = allocate(sizeof(struct ref));
refp->name = extp->op->filedef_name;
refp->next = object_list[i]->refs;
object_list[i]->refs = refp;
}
}
}
}
for(j = 0;
j < object_list[i]->pu_nsymbols;
j++){
p = object_list[i]->pu_symbols[j].n_un.n_name;
hash_key = hash_string(p) % EXT_HASH_SIZE;
extp = ext_hash[hash_key];
while(extp != (struct ext *)0){
if(strcmp(p, extp->name) == 0)
break;
extp = extp->next;
}
if(extp == (struct ext *)0)
fatal("symbol: %s in object: %s not found in target "
"shared library: %s", p, object_list[i]->name,
target_filename);
if(extp->alias != (struct ext *)0)
extp = extp->alias;
if(extp->op != (struct object *)0){
refp = object_list[i]->refs;
while(refp != (struct ref *)0){
if(strcmp(refp->name, extp->op->filedef_name) == 0)
break;
refp = refp->next;
}
if(refp == (struct ref *)0){
refp = allocate(sizeof(struct ref));
refp->name = extp->op->filedef_name;
refp->next = object_list[i]->refs;
object_list[i]->refs = refp;
}
}
}
}
#ifdef HOST_DEBUG
printf("References from host objects to each other\n");
for(i = 0; i < nobject_list; i++){
printf("\tObject: %s references:\n", object_list[i]->name);
refp = object_list[i]->refs;
while(refp != (struct ref *)0){
printf("\t\t%s\n", refp->name);
refp = refp->next;
}
}
#endif
}
static
void
build_archive(void)
{
unsigned long ran_index, ran_strx, ran_off, i, j;
struct object *op;
char *symbol_name;
build_lib_object();
build_ref_object();
build_host_objects();
toc_object.ranlibs = allocate(toc_object.nranlibs *
sizeof(struct ranlib));
toc_object.ranlib_strings =
allocate(round(toc_object.ranlib_string_size, sizeof(long)));
memset(toc_object.ranlib_strings + toc_object.ranlib_string_size, '\0',
round(toc_object.ranlib_string_size, sizeof(long)) -
toc_object.ranlib_string_size);
toc_object.object_size =
sizeof(long) +
toc_object.nranlibs * sizeof(struct ranlib) +
sizeof(long) +
round(toc_object.ranlib_string_size, sizeof(long));
ran_index = 0;
ran_strx = 0;
ran_off = SARMAG + sizeof(struct ar_hdr) + toc_object.object_size;
toc_object.ranlibs[ran_index].ran_un.ran_strx = ran_strx;
toc_object.ranlibs[ran_index].ran_off = ran_off;
strcpy(toc_object.ranlib_strings + ran_strx, shlib_symbol_name);
ran_index++;
ran_strx += strlen(shlib_symbol_name) + 1;
ran_off += sizeof(struct ar_hdr) + lib_object.object_size;
toc_object.ranlibs[ran_index].ran_un.ran_strx = ran_strx;
toc_object.ranlibs[ran_index].ran_off = ran_off;
strcpy(toc_object.ranlib_strings + ran_strx, shlib_reference_name);
ran_index++;
ran_strx += strlen(shlib_reference_name) + 1;
ran_off += sizeof(struct ar_hdr) + ref_object.object_size;
for(i = 0; i < nobject_list; i++){
op = object_list[i];
for(j = 0; j < op->nsymbols; j++){
if((op->symbols[j].n_type & N_TYPE) != N_UNDF){
symbol_name = op->strings + op->symbols[j].n_un.n_strx;
toc_object.ranlibs[ran_index].ran_un.ran_strx = ran_strx;
toc_object.ranlibs[ran_index].ran_off = ran_off;
strcpy(toc_object.ranlib_strings + ran_strx, symbol_name);
ran_index++;
ran_strx += strlen(symbol_name) + 1;
}
}
ran_off += sizeof(struct ar_hdr) + op->object_size;
}
host_lib_size = ran_off;
if(ran_index != toc_object.nranlibs)
fatal("internal error: ran_index (%ld) not equal to "
"toc_object.nranlibs (%ld)", ran_index, toc_object.nranlibs);
if(ran_strx != toc_object.ranlib_string_size)
fatal("internal error: ran_strx (%ld) not equal to "
"toc_object.ranlib_string_size (%ld)", ran_strx,
toc_object.ranlib_string_size);
toc_object.ranlib_string_size = round(toc_object.ranlib_string_size,
sizeof(long));
qsort(toc_object.ranlibs, toc_object.nranlibs, sizeof(struct ranlib),
(int (*)(const void *, const void *))ranlib_qsort);
}
static
int
ranlib_qsort(
const struct ranlib *ran1,
const struct ranlib *ran2)
{
return(strcmp(toc_object.ranlib_strings + ran1->ran_un.ran_strx,
toc_object.ranlib_strings + ran2->ran_un.ran_strx));
}
static
void
build_lib_object(void)
{
unsigned long i;
struct load_command *lc;
lib_object.nfvmsegs = 0;
lc = (struct load_command *)load_commands;
for(i = 0; i < target_mh.ncmds; i++){
if(lc->cmd == LC_SEGMENT){
lib_object.nfvmsegs++;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
lib_object.fvmlib_name_size = round(strlen(target_name) + 1,
sizeof(long));
toc_object.nranlibs++;
toc_object.ranlib_string_size += strlen(shlib_symbol_name) + 1;
lib_object.string_size = round(strlen(shlib_symbol_name) + 2,
sizeof(long));
lib_object.object_size =
sizeof(struct mach_header) +
lib_object.nfvmsegs * sizeof(struct segment_command) +
sizeof(struct symtab_command) +
sizeof(struct fvmlib_command) +
lib_object.fvmlib_name_size +
sizeof(struct nlist) +
lib_object.string_size;
}
static
void
build_ref_object(void)
{
unsigned long i;
toc_object.nranlibs++;
toc_object.ranlib_string_size += strlen(shlib_reference_name) + 1;
ref_object.string_size = 1;
ref_object.string_size += strlen(shlib_reference_name) + 2;
for(i = 0; i < nobject_list; i++)
ref_object.string_size += strlen(object_list[i]->filedef_name) + 1;
ref_object.string_size = round(ref_object.string_size, sizeof(long));
ref_object.object_size =
sizeof(struct mach_header) +
sizeof(struct symtab_command) +
sizeof(struct nlist) * (1 + nobject_list) +
ref_object.string_size;
}
static
void
build_host_objects(void)
{
unsigned long i, j, strx, hash_key, len, new_symbols, new_string_size;
char *p;
struct object *op;
struct ref *refp;
struct ext *extp;
struct init *ip;
for(i = 0; i < nobject_list; i++){
op = object_list[i];
strx = 1;
for(j = 0; j < op->nsymbols; j++){
len = strlen(op->symbols[j].n_un.n_name) + 1;
if((op->symbols[j].n_type & N_TYPE) != N_UNDF){
p = op->symbols[j].n_un.n_name;
hash_key = hash_string(p) % EXT_HASH_SIZE;
extp = ext_hash[hash_key];
while(extp != (struct ext *)0){
if(strcmp(p, extp->name) == 0)
break;
extp = extp->next;
}
if(extp == (struct ext *)0)
fatal("symbol: %s in object: %s not found in target "
"shared library: %s", p, object_list[i]->name,
target_filename);
if(extp->bp != (struct branch *)0)
op->symbols[j].n_value = extp->branch_value;
else
op->symbols[j].n_value = extp->value;
op->symbols[j].n_type = N_ABS | N_EXT;
op->symbols[j].n_sect = NO_SECT;
toc_object.nranlibs++;
toc_object.ranlib_string_size += len;
}
op->symbols[j].n_un.n_strx = strx;
strx += len;
}
new_symbols = 0;
if(object_list[i]->string_size == 0)
new_string_size = 1;
else
new_string_size = 0;
op->ninit = 0;
if(op->inits != (struct init *)0){
ip = op->inits;
while(ip != (struct init *)0){
init_symbol(op, ip->sinit, &(ip->sreloc), &(ip->svalue),
&(ip->sdefined), op->nsymbols + new_symbols,
(op->ninit * 2) * sizeof(long));
if(!ip->sdefined){
new_symbols++;
new_string_size += strlen(ip->sinit) + 1;
}
init_symbol(op, ip->pinit, &(ip->preloc), &(ip->pvalue),
&(ip->pdefined), op->nsymbols + new_symbols,
(op->ninit * 2 + 1) * sizeof(long));
if(!ip->pdefined){
new_symbols++;
new_string_size += strlen(ip->pinit) + 1;
}
op->ninit++;
ip = ip->next;
}
}
refp = op->refs;
while(refp != (struct ref *)0){
new_symbols++;
new_string_size += strlen(refp->name) + 1;
refp = refp->next;
}
new_symbols++;
len = strlen(op->filedef_name) + 1;
new_string_size += len;
toc_object.nranlibs++;
toc_object.ranlib_string_size += len;
new_symbols++;
new_string_size += strlen(shlib_symbol_name) + 1;
object_list[i]->symbols =
reallocate(object_list[i]->symbols,
(object_list[i]->nsymbols + new_symbols) *
sizeof(struct nlist));
object_list[i]->strings =
reallocate(object_list[i]->strings,
round(object_list[i]->string_size +
new_string_size, sizeof(long)));
memset(object_list[i]->strings +
object_list[i]->string_size + new_string_size, '\0',
round(object_list[i]->string_size + new_string_size,
sizeof(long)) -
(object_list[i]->string_size + new_string_size) );
object_list[i]->string_size = round(object_list[i]->string_size +
new_string_size, sizeof(long));
if(op->inits != (struct init *)0){
ip = op->inits;
while(ip != (struct init *)0){
if(!ip->sdefined){
op->symbols[op->nsymbols].n_un.n_strx = strx;
op->symbols[op->nsymbols].n_type = N_UNDF | N_EXT;
op->symbols[op->nsymbols].n_sect = NO_SECT;
op->symbols[op->nsymbols].n_desc = 0;
op->symbols[op->nsymbols].n_value = 0;
strcpy(op->strings + strx, ip->sinit);
op->nsymbols++;
strx += strlen(ip->sinit) + 1;
}
if(!ip->pdefined){
op->symbols[op->nsymbols].n_un.n_strx = strx;
op->symbols[op->nsymbols].n_type = N_UNDF | N_EXT;
op->symbols[op->nsymbols].n_sect = NO_SECT;
op->symbols[op->nsymbols].n_desc = 0;
op->symbols[op->nsymbols].n_value = 0;
strcpy(op->strings + strx, ip->pinit);
op->nsymbols++;
strx += strlen(ip->pinit) + 1;
}
ip = ip->next;
}
}
refp = op->refs;
while(refp != (struct ref *)0){
op->symbols[op->nsymbols].n_un.n_strx = strx;
op->symbols[op->nsymbols].n_type = N_UNDF | N_EXT;
op->symbols[op->nsymbols].n_sect = NO_SECT;
op->symbols[op->nsymbols].n_desc = 0;
op->symbols[op->nsymbols].n_value = 0;
strcpy(op->strings + strx, refp->name);
op->nsymbols++;
strx += strlen(refp->name) + 1;
refp = refp->next;
}
op->symbols[op->nsymbols].n_un.n_strx = strx;
op->symbols[op->nsymbols].n_type = N_ABS | N_EXT;
op->symbols[op->nsymbols].n_sect = NO_SECT;
op->symbols[op->nsymbols].n_desc = 0;
op->symbols[op->nsymbols].n_value = 0;
strcpy(op->strings + strx, op->filedef_name);
op->nsymbols++;
strx += strlen(op->filedef_name) + 1;
op->symbols[op->nsymbols].n_un.n_strx = strx;
op->symbols[op->nsymbols].n_type = N_UNDF | N_EXT;
op->symbols[op->nsymbols].n_sect = NO_SECT;
op->symbols[op->nsymbols].n_desc = 0;
op->symbols[op->nsymbols].n_value = 0;
strcpy(op->strings + strx, shlib_symbol_name);
op->nsymbols++;
strx += strlen(shlib_symbol_name) + 1;
op->object_size = sizeof(struct mach_header) +
sizeof(struct segment_command) +
sizeof(struct section) +
sizeof(struct symtab_command) +
op->ninit * 2 * sizeof(long) +
op->ninit * 2 * sizeof(struct relocation_info) +
op->nsymbols * sizeof(struct nlist) +
op->string_size;
}
}
static
void
init_symbol(
struct object *op,
char *name,
struct relocation_info *reloc,
long *value,
long *defined,
long symbolnum,
long address)
{
long hash_key;
struct ext *extp;
hash_key = hash_string(name) % EXT_HASH_SIZE;
extp = ext_hash[hash_key];
while(extp != (struct ext *)0){
if(strcmp(name, extp->name) == 0)
break;
extp = extp->next;
}
if(extp == (struct ext *)0 || extp->op != op){
reloc->r_address = address;
reloc->r_symbolnum = symbolnum;
reloc->r_pcrel = 0;
reloc->r_length = 2;
reloc->r_extern = 1;
reloc->r_type = 0;
*value = 0;
*defined = 0;
}
else{
reloc->r_address = address;
reloc->r_symbolnum = R_ABS;
reloc->r_pcrel = 0;
reloc->r_length = 2;
reloc->r_extern = 0;
reloc->r_type = 0;
if(extp->bp != (struct branch *)0)
*value = extp->branch_value;
else
*value = extp->value;
*defined = 1;
}
}
static
void
write_archive(void)
{
int fd;
kern_return_t r;
char *buffer;
unsigned long offset;
struct stat stat;
long mtime, symdef_mtime, mode;
uid_t uid;
gid_t gid;
struct ar_hdr ar_hdr;
unsigned long i, l;
struct object *op;
struct ranlib *ranlibs;
(void)unlink(host_filename);
if((fd = open(host_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1)
system_fatal("can't create file: %s", host_filename);
if((r = vm_allocate(mach_task_self(), (vm_address_t *)&buffer,
host_lib_size, TRUE)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_allocate() buffer for host library of size "
"%ld", host_lib_size);
if(fstat(fd, &stat) == -1)
system_fatal("can't stat host library file: %s", host_filename);
mtime = time(0);
symdef_mtime = (mtime > stat.st_mtime) ? mtime + 5 : stat.st_mtime + 5;
uid = getuid();
gid = getgid();
mode = stat.st_mode & 0777;
offset = 0;
memcpy(buffer + offset, ARMAG, SARMAG);
offset += SARMAG;
sprintf(buffer + offset, "%-*.*s%-*ld%-*u%-*u%-*o%-*ld%-*s",
(int)sizeof(ar_hdr.ar_name),
(int)sizeof(ar_hdr.ar_name),
SYMDEF_SORTED,
(int)sizeof(ar_hdr.ar_date),
symdef_mtime,
(int)sizeof(ar_hdr.ar_uid),
(unsigned int)uid,
(int)sizeof(ar_hdr.ar_gid),
(unsigned int)gid,
(int)sizeof(ar_hdr.ar_mode),
(unsigned int)mode,
(int)sizeof(ar_hdr.ar_size),
toc_object.object_size,
(int)sizeof(ar_hdr.ar_fmag),
ARFMAG);
offset += sizeof(struct ar_hdr);
l = toc_object.nranlibs * sizeof(struct ranlib);
if(host_byte_sex != target_byte_sex)
l = SWAP_LONG(l);
*((long *)(buffer + offset)) = l;
offset += sizeof(long);
ranlibs = (struct ranlib *)(buffer + offset);
memcpy(buffer + offset, toc_object.ranlibs,
toc_object.nranlibs * sizeof(struct ranlib));
if(host_byte_sex != target_byte_sex)
swap_ranlib(ranlibs, toc_object.nranlibs, target_byte_sex);
offset += toc_object.nranlibs * sizeof(struct ranlib);
l = toc_object.ranlib_string_size;
if(host_byte_sex != target_byte_sex)
l = SWAP_LONG(l);
*((long *)(buffer + offset)) = l;
offset += sizeof(long);
memcpy(buffer + offset, toc_object.ranlib_strings,
toc_object.ranlib_string_size);
offset += toc_object.ranlib_string_size;
sprintf(buffer + offset, "%-*.*s%-*ld%-*u%-*u%-*o%-*ld%-*s",
(int)sizeof(ar_hdr.ar_name),
(int)sizeof(ar_hdr.ar_name),
"__.FVMLIB",
(int)sizeof(ar_hdr.ar_date),
mtime,
(int)sizeof(ar_hdr.ar_uid),
(unsigned int)uid,
(int)sizeof(ar_hdr.ar_gid),
(unsigned int)gid,
(int)sizeof(ar_hdr.ar_mode),
(unsigned int)mode,
(int)sizeof(ar_hdr.ar_size),
lib_object.object_size,
(int)sizeof(ar_hdr.ar_fmag),
ARFMAG);
offset += sizeof(struct ar_hdr);
write_lib_obj(buffer + offset);
offset += lib_object.object_size;
sprintf(buffer + offset, "%-*.*s%-*ld%-*u%-*u%-*o%-*ld%-*s",
(int)sizeof(ar_hdr.ar_name),
(int)sizeof(ar_hdr.ar_name),
"__.FVMLIB_REF",
(int)sizeof(ar_hdr.ar_date),
mtime,
(int)sizeof(ar_hdr.ar_uid),
(unsigned int)uid,
(int)sizeof(ar_hdr.ar_gid),
(unsigned int)gid,
(int)sizeof(ar_hdr.ar_mode),
(unsigned int)mode,
(int)sizeof(ar_hdr.ar_size),
ref_object.object_size,
(int)sizeof(ar_hdr.ar_fmag),
ARFMAG);
offset += sizeof(struct ar_hdr);
write_ref_obj(buffer + offset);
offset += ref_object.object_size;
for(i = 0; i < nobject_list; i++){
op = object_list[i];
sprintf(buffer + offset, "%-*.*s%-*ld%-*u%-*u%-*o%-*ld%-*s",
(int)sizeof(ar_hdr.ar_name),
(int)sizeof(ar_hdr.ar_name),
op->base_name,
(int)sizeof(ar_hdr.ar_date),
mtime,
(int)sizeof(ar_hdr.ar_uid),
(unsigned int)uid,
(int)sizeof(ar_hdr.ar_gid),
(unsigned int)gid,
(int)sizeof(ar_hdr.ar_mode),
(unsigned int)mode,
(int)sizeof(ar_hdr.ar_size),
op->object_size,
(int)sizeof(ar_hdr.ar_fmag),
ARFMAG);
offset += sizeof(struct ar_hdr);
write_object(op, buffer + offset);
offset += op->object_size;
}
if(write(fd, buffer, host_lib_size) != host_lib_size)
system_fatal("can't write host library file: %s", host_filename);
#ifdef OS_BUG
fsync(fd);
#endif
if(close(fd) == -1)
system_fatal("can't close file: %s", host_filename);
if((r = vm_deallocate(mach_task_self(), (vm_address_t)buffer,
host_lib_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() buffer for host library");
}
static
void
write_lib_obj(
char *buffer)
{
unsigned long offset, i;
struct mach_header *mh;
struct load_command *lc, *lib_obj_load_commands;
struct segment_command *sg;
struct fvmlib_command *fvmlib;
struct symtab_command *st;
struct nlist *symbol;
offset = 0;
mh = (struct mach_header *)(buffer + offset);
mh->magic = MH_MAGIC;
mh->cputype = arch_flag.cputype;
mh->cpusubtype = arch_flag.cpusubtype;
mh->filetype = MH_OBJECT;
mh->ncmds = 2 + lib_object.nfvmsegs;
mh->sizeofcmds = lib_object.nfvmsegs * sizeof(struct segment_command) +
sizeof(struct symtab_command) +
sizeof(struct fvmlib_command) +
lib_object.fvmlib_name_size;
mh->flags = MH_NOUNDEFS;
offset += sizeof(struct mach_header);
lc = (struct load_command *)load_commands;
lib_obj_load_commands = (struct load_command *)(buffer + offset);
for(i = 0; i < target_mh.ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)(buffer + offset);
*sg = *((struct segment_command *)lc);
if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
sg->vmsize = 0;
sg->cmdsize = sizeof(struct segment_command);
sg->fileoff = 0;
sg->filesize = 0;
sg->nsects = 0;
sg->flags = SG_FVMLIB;
offset += sizeof(struct segment_command);
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
fvmlib = (struct fvmlib_command *)(buffer + offset);
fvmlib->cmd = LC_LOADFVMLIB;
fvmlib->cmdsize = sizeof(struct fvmlib_command) +
lib_object.fvmlib_name_size;
fvmlib->fvmlib.name.offset = sizeof(struct fvmlib_command);
fvmlib->fvmlib.minor_version = minor_version;
fvmlib->fvmlib.header_addr = text_addr;
offset += sizeof(struct fvmlib_command);
strcpy(buffer + offset, target_name);
offset += lib_object.fvmlib_name_size;
st = (struct symtab_command *)(buffer + offset);
st->cmd = LC_SYMTAB;
st->cmdsize = sizeof(struct symtab_command);
st->symoff = sizeof(struct mach_header) + mh->sizeofcmds;
st->nsyms = 1;
st->stroff = st->symoff + sizeof(struct nlist);
st->strsize = lib_object.string_size;
offset += sizeof(struct symtab_command);
symbol = (struct nlist *)(buffer + offset);
symbol->n_un.n_strx = 1;
symbol->n_type = N_ABS | N_EXT;
symbol->n_sect = NO_SECT;
symbol->n_desc = 0;
symbol->n_value = 0;
offset += sizeof(struct nlist);
strcpy(buffer + offset + 1, shlib_symbol_name);
offset += lib_object.string_size;
if(host_byte_sex != target_byte_sex){
if(swap_object_headers(mh, lib_obj_load_commands) == FALSE)
fatal("internal error: swap_object_headers() failed");
swap_nlist(symbol, 1, target_byte_sex);
}
}
static
void
write_ref_obj(
char *buffer)
{
unsigned long offset, strx, i;
struct mach_header *mh;
struct symtab_command *st;
struct nlist *symbols, *first_symbol;
char *strings;
offset = 0;
mh = (struct mach_header *)(buffer + offset);
mh->magic = MH_MAGIC;
mh->cputype = arch_flag.cputype;
mh->cpusubtype = arch_flag.cpusubtype;
mh->filetype = MH_OBJECT;
mh->ncmds = 1;
mh->sizeofcmds = sizeof(struct symtab_command);
mh->flags = 0;
offset += sizeof(struct mach_header);
st = (struct symtab_command *)(buffer + offset);
st->cmd = LC_SYMTAB;
st->cmdsize = sizeof(struct symtab_command);
st->symoff = sizeof(struct mach_header) + mh->sizeofcmds;
st->nsyms = 1 + nobject_list;
st->stroff = st->symoff + (st->nsyms * sizeof(struct nlist));
st->strsize = ref_object.string_size;
offset += sizeof(struct symtab_command);
strings = (char *)(buffer + st->stroff);
symbols = (struct nlist *)(buffer + st->symoff);
first_symbol = symbols;
strx = 1;
symbols->n_un.n_strx = strx;
strcpy(strings + strx, shlib_reference_name);
strx += strlen(shlib_reference_name) + 1;
symbols->n_type = N_ABS | N_EXT;
symbols->n_sect = NO_SECT;
symbols->n_desc = 0;
symbols->n_value = 0;
symbols++;
for(i = 0; i < nobject_list; i++){
symbols->n_un.n_strx = strx;
strcpy(strings + strx, object_list[i]->filedef_name);
strx += strlen(object_list[i]->filedef_name) + 1;
symbols->n_type = N_UNDF | N_EXT;
symbols->n_sect = NO_SECT;
symbols->n_desc = 0;
symbols->n_value = 0;
symbols++;
}
if(host_byte_sex != target_byte_sex){
swap_mach_header(mh, target_byte_sex);
swap_symtab_command(st, target_byte_sex);
swap_nlist(first_symbol, 1 + nobject_list, target_byte_sex);
}
}
static
void
write_object(
struct object *op,
char *buffer)
{
long offset;
struct mach_header *mh;
struct segment_command *sg;
struct section *s;
struct symtab_command *st;
struct init *ip;
long *contents;
struct nlist *symbols;
struct relocation_info *reloc, *relocs;
offset = 0;
mh = (struct mach_header *)(buffer + offset);
mh->magic = MH_MAGIC;
mh->cputype = arch_flag.cputype;
mh->cpusubtype = arch_flag.cpusubtype;
mh->filetype = MH_OBJECT;
mh->ncmds = 2;
mh->sizeofcmds = sizeof(struct segment_command) +
sizeof(struct section) +
sizeof(struct symtab_command);
mh->flags = 0;
offset += sizeof(struct mach_header);
sg = (struct segment_command *)(buffer + offset);
sg->cmd = LC_SEGMENT;
sg->cmdsize = sizeof(struct segment_command) + sizeof(struct section);
sg->vmaddr = 0;
sg->vmsize = op->ninit * 2 * sizeof(long);
sg->fileoff = sizeof(struct mach_header) + mh->sizeofcmds;
sg->filesize = op->ninit * 2 * sizeof(long);
sg->maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
sg->initprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
sg->nsects = 1;
sg->flags = 0;
offset += sizeof(struct segment_command);
s = (struct section *)(buffer + offset);
strcpy(s->sectname, SECT_FVMLIB_INIT0);
strcpy(s->segname, SEG_TEXT);
s->addr = 0;
s->size = op->ninit * 2 * sizeof(long);
s->offset = sizeof(struct mach_header) + mh->sizeofcmds;
s->align = 2;
s->reloff = sizeof(struct mach_header) + mh->sizeofcmds +
op->ninit * 2 * sizeof(long);
s->nreloc = op->ninit * 2;
s->flags = 0;
s->reserved1 = 0;
s->reserved2 = 0;
offset += sizeof(struct section);
st = (struct symtab_command *)(buffer + offset);
st->cmd = LC_SYMTAB;
st->cmdsize = sizeof(struct symtab_command);
st->symoff = sizeof(struct mach_header) +
mh->sizeofcmds +
op->ninit * 2 * sizeof(long) +
op->ninit * 2 * sizeof(struct relocation_info);
st->nsyms = op->nsymbols;
st->stroff = sizeof(struct mach_header) +
mh->sizeofcmds +
op->ninit * 2 * sizeof(long) +
op->ninit * 2 * sizeof(struct relocation_info) +
op->nsymbols * sizeof(struct nlist);
st->strsize = op->string_size;
offset += sizeof(struct symtab_command);
if(op->inits != (struct init *)0){
ip = op->inits;
while(ip != (struct init *)0){
contents = (long *)(buffer + offset);
if(host_byte_sex != target_byte_sex)
*contents = SWAP_LONG(ip->svalue);
else
*contents = ip->svalue;
offset += sizeof(long);
contents = (long *)(buffer + offset);
if(host_byte_sex != target_byte_sex)
*contents = SWAP_LONG(ip->pvalue);
else
*contents = ip->pvalue;
offset += sizeof(long);
ip = ip->next;
}
}
relocs = (struct relocation_info *)(buffer + offset);
if(op->inits != (struct init *)0){
ip = op->inits;
while(ip != (struct init *)0){
reloc = (struct relocation_info *)(buffer + offset);
*reloc = ip->sreloc;
offset += sizeof(struct relocation_info);
reloc = (struct relocation_info *)(buffer + offset);
*reloc = ip->preloc;
offset += sizeof(struct relocation_info);
ip = ip->next;
}
}
symbols = (struct nlist *)(buffer + offset);
memcpy(buffer + offset, op->symbols,
op->nsymbols * sizeof(struct nlist));
offset += op->nsymbols * sizeof(struct nlist);
memcpy(buffer + offset, op->strings, op->string_size);
offset += op->string_size;
if(host_byte_sex != target_byte_sex){
swap_mach_header(mh, target_byte_sex);
swap_segment_command(sg, target_byte_sex);
swap_section(s, 1, target_byte_sex);
swap_symtab_command(st, target_byte_sex);
swap_relocation_info(relocs, op->ninit * 2, target_byte_sex);
swap_nlist(symbols, op->nsymbols, target_byte_sex);
}
}