#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libc.h>
#include <sys/file.h>
#include <mach/mach.h>
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#include <mach-o/reloc.h>
#include "stuff/arch.h"
#include "stuff/errors.h"
#include "stuff/allocate.h"
#include "libgcc.h"
#include "mkshlib.h"
extern char *mktemp();
char *branch_source_filename;
char *branch_object_filename;
char *lib_id_object_filename;
static char *branch = NULL;
static char *trap = NULL;
static unsigned long branch_slot_size = 0;
static void build_branch_object(void);
static void build_lib_id_object(void);
void
target(void)
{
int fd;
unsigned long magic;
struct mach_header mh;
char text_addr_string[10], data_addr_string[10];
struct alias *ap;
struct oddball *obp;
unsigned long i;
const struct arch_flag *family_arch_flag;
if(arch_flag.name == NULL && nobject_list == 0)
if(get_arch_from_host(&arch_flag, NULL) == 0)
fatal("can't determine the host architecture (specify an "
"-arch flag or fix get_arch_from_host() )");
if(arch_flag.name == NULL){
if((fd = open(object_list[0]->name, O_RDONLY, 0)) == -1)
system_fatal("can't open object file: %s",
object_list[0]->name);
if(read(fd, &magic, sizeof(unsigned long)) !=
sizeof(unsigned long))
system_fatal("can't read magic number of object file: %s",
object_list[0]->name);
#ifdef __BIG_ENDIAN__
if(magic == FAT_MAGIC)
#endif
#ifdef __LITTLE_ENDIAN__
if(magic == SWAP_LONG(FAT_MAGIC))
#endif
{
fatal("-arch must be specified with use of fat files");
}
else if(magic == MH_MAGIC || magic == SWAP_LONG(MH_MAGIC)){
lseek(fd, 0, L_SET);
if(read(fd, &mh, sizeof(struct mach_header)) !=
sizeof(struct mach_header))
system_fatal("can't read mach_header of object file: "
"%s", object_list[0]->name);
if(magic == SWAP_LONG(MH_MAGIC))
swap_mach_header(&mh, host_byte_sex);
arch_flag.cputype = mh.cputype;
arch_flag.cpusubtype = mh.cpusubtype;
}
else
fatal("first file listed in #object directive: %s is not "
"an object file (bad magic number)",
object_list[0]->name);
close(fd);
}
if(arch_flag.cputype == CPU_TYPE_MC680x0){
branch = "jmp";
trap = "trapt.l\t#0xfeadface";
target_byte_sex = BIG_ENDIAN_BYTE_SEX;
branch_slot_size = 6;
}
else if(arch_flag.cputype == CPU_TYPE_POWERPC){
branch = "b";
trap = ".long 0";
target_byte_sex = BIG_ENDIAN_BYTE_SEX;
branch_slot_size = 4;
}
else if(arch_flag.cputype == CPU_TYPE_MC88000){
branch = "br";
trap = "illop1";
target_byte_sex = BIG_ENDIAN_BYTE_SEX;
branch_slot_size = 4;
}
else if(arch_flag.cputype == CPU_TYPE_I386){
branch = "jmp";
trap = ".byte 0xf4,0xf4,0xf4,0xf4,0xf4";
target_byte_sex = LITTLE_ENDIAN_BYTE_SEX;
branch_slot_size = 5;
}
else if(arch_flag.cputype == CPU_TYPE_HPPA){
trap = "break 0,0\nbreak 0,0";
target_byte_sex = BIG_ENDIAN_BYTE_SEX;
branch_slot_size = 8;
}
else if(arch_flag.cputype == CPU_TYPE_SPARC){
branch = "ba,a";
trap = "ta 0";
target_byte_sex = BIG_ENDIAN_BYTE_SEX;
branch_slot_size = 4;
}
else{
if(arch_flag.name == NULL)
fatal("unknown or unsupported cputype (%d) in object file: "
"%s", mh.cputype, object_list[0]->name);
else
fatal("unsupported architecture for -arch %s", arch_flag.name);
}
family_arch_flag = get_arch_family_from_cputype(arch_flag.cputype);
if(family_arch_flag != NULL){
arch_flag.name = (char *)(family_arch_flag->name);
arch_flag.cpusubtype = family_arch_flag->cpusubtype;
}
build_branch_object();
build_lib_id_object();
for(i = 0; i < nobject_list; i++){
if(access(object_list[i]->name, R_OK) == -1)
system_error("can't read object file: %s",
object_list[i]->name);
}
if(errors)
cleanup(0);
reset_runlist();
add_runlist(ldname);
add_runlist("-arch");
add_runlist(arch_flag.name);
add_runlist("-fvmlib");
for(i = 0; i < ODDBALL_HASH_SIZE; i++){
obp = oddball_hash[i];
while(obp != (struct oddball *)0){
if(obp->undefined){
add_runlist("-U");
add_runlist(obp->name);
}
obp = obp->next;
}
}
ap = aliases;
while(ap != (struct alias *)0){
add_runlist(makestr("-i", ap->alias_name, ":", ap->real_name,
(char *)0) );
ap = ap->next;
}
add_runlist("-segaddr");
add_runlist(SEG_TEXT);
sprintf(text_addr_string, "%x", (unsigned int)text_addr);
add_runlist(text_addr_string);
add_runlist("-segaddr");
add_runlist(SEG_DATA);
sprintf(data_addr_string, "%x", (unsigned int)data_addr);
add_runlist(data_addr_string);
for(i = 0; i < nldflags; i++)
add_runlist(ldflags[i]);
add_runlist("-o");
add_runlist(target_filename);
add_runlist(branch_object_filename);
add_runlist(lib_id_object_filename);
for(i = 0; i < nobject_list; i++)
add_runlist(object_list[i]->name);
if(run())
fatal("internal link edit using: %s failed", ldname);
if(!dflag)
unlink(lib_id_object_filename);
}
static
void
build_branch_object(void)
{
long i, text_size, pad;
FILE *stream;
char *p;
struct shlib_info shlib;
branch_source_filename = "branch.s";
branch_object_filename = "branch.o";
(void)unlink(branch_source_filename);
if((stream = fopen(branch_source_filename, "w")) == NULL)
system_fatal("can't create temporary file: %s for branch table "
"assembly source", branch_source_filename);
if(fprintf(stream, "\t.text\n") == EOF)
system_fatal("can't write to temporary file: %s (branch table "
"assembly source)", branch_source_filename);
if(fprintf(stream, "\t.globl %s\n%s:\n", shlib_symbol_name,
shlib_symbol_name) == EOF)
system_fatal("can't write to temporary file: %s (branch table "
"assembly source)", branch_source_filename);
if(fprintf(stream, SHLIB_STRUCT, text_addr, 0, data_addr, 0,
minor_version, target_name, sizeof(shlib.name) -
(strlen(target_name) + 1)) == EOF)
system_fatal("can't write to temporary file: %s (branch table "
"assembly source)", branch_source_filename);
for(i = 0; i < nbranch_list; i++){
if(branch_list[i]->empty_slot){
if(fprintf(stream, "\t%s\n", trap) == EOF)
system_fatal("can't write to temporary file: %s (branch "
"table assembly source)",
branch_source_filename);
}
else{
p = branch_slot_symbol(i);
if(fprintf(stream, "\t.globl %s\n%s:",p,p) == EOF)
system_fatal("can't write to temporary file: %s (branch "
"table assembly source)",
branch_source_filename);
if(arch_flag.cputype == CPU_TYPE_HPPA) {
if (fprintf(stream,"\tldil L`%s,%%r1\n\tbe,n R`%s(%%sr4,%%r1)\n",
branch_list[i]->name,
branch_list[i]->name) == EOF)
system_fatal("can't write to temporary file: %s (branch "
"table assembly source)",
branch_source_filename);
}
else {
if (fprintf(stream,"\t%s\t%s\n",
branch,branch_list[i]->name) == EOF)
system_fatal("can't write to temporary file: %s (branch "
"table assembly source)",
branch_source_filename);
}
}
}
text_size = sizeof(struct shlib_info) + nbranch_list * branch_slot_size;
pad = round(text_size, 4) - text_size;
for(i = 0; i < pad; i++){
if(fprintf(stream, "\t.byte 0\n") == EOF)
system_fatal("can't write to temporary file: %s (branch table "
"assembly source)", branch_source_filename);
}
if(fclose(stream) == EOF)
system_fatal("can't close temporary file: %s for branch table "
"assembly source", branch_source_filename);
reset_runlist();
add_runlist(asname);
add_runlist("-arch");
add_runlist(arch_flag.name);
add_runlist("-o");
add_runlist(branch_object_filename);
add_runlist(branch_source_filename);
if(run())
fatal("internal assembly using: %s failed", asname);
}
static
void
build_lib_id_object(void)
{
int fd;
long fvmlib_name_size, object_size, offset;
char *buffer;
struct mach_header *mh;
struct fvmlib_command *fvmlib;
if(dflag){
lib_id_object_filename = "lib_id.o";
}
else{
lib_id_object_filename = mktemp(savestr("mkshlib_lid_XXXXXX"));
}
(void)unlink(lib_id_object_filename);
if((fd = open(lib_id_object_filename, O_WRONLY | O_CREAT | O_TRUNC,
0666)) == -1)
system_fatal("can't create file: %s", lib_id_object_filename);
fvmlib_name_size = round(strlen(target_name) + 1, sizeof(long));
object_size = sizeof(struct mach_header) +
sizeof(struct fvmlib_command) +
fvmlib_name_size;
buffer = allocate(object_size);
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 fvmlib_command) +
fvmlib_name_size;
mh->flags = MH_NOUNDEFS;
offset += sizeof(struct mach_header);
fvmlib = (struct fvmlib_command *)(buffer + offset);
fvmlib->cmd = LC_IDFVMLIB;
fvmlib->cmdsize = sizeof(struct fvmlib_command) +
fvmlib_name_size;
fvmlib->fvmlib.name.offset = sizeof(struct fvmlib_command);
if(image_version != 0)
fvmlib->fvmlib.minor_version = image_version;
else
fvmlib->fvmlib.minor_version = minor_version;
fvmlib->fvmlib.header_addr = text_addr;
offset += sizeof(struct fvmlib_command);
strcpy(buffer + offset, target_name);
offset += fvmlib_name_size;
if(host_byte_sex != target_byte_sex){
swap_mach_header(mh, target_byte_sex);
swap_fvmlib_command(fvmlib, target_byte_sex);
}
if(write(fd, buffer, object_size) != object_size)
system_fatal("can't write file: %s", lib_id_object_filename);
if(close(fd) == -1)
system_fatal("can't close file: %s", lib_id_object_filename);
free(buffer);
}