cctools-port/cctools/misc/indr.c
2020-03-20 13:33:04 +01:00

1859 lines
54 KiB
C

/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include <libc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <mach-o/nlist.h>
#include "stuff/breakout.h"
#include "stuff/hash_string.h"
#include "stuff/allocate.h"
#include "stuff/errors.h"
#include "stuff/rnd.h"
#include "stuff/reloc.h"
char *progname = NULL; /* name of the program for error messages (argv[0]) */
/*
* If -arch_indr <arch> <listfile> is used then this is an allocated array of
* the names of the listfiles.
*/
char **list_filenames = NULL;
/*
* Data structures to hold the symbol names (both the indirect and undefined
* symbol names) from the list file.
*/
struct symbol {
char *name; /* name of the symbol */
int32_t type; /* type of this symbol (N_INDR or N_UNDF) */
char *indr; /* name for indirection if N_INDR type */
struct indr_object *io; /* pointer to indr_object for this */
struct symbol *next; /* next symbol in the hash chain */
};
/* The symbol hash table is hashed on the name field */
#define SYMBOL_HASH_SIZE 250
static struct symbol *symbol_hash[SYMBOL_HASH_SIZE];
/*
* Data structures to hold the object names (both the names from the archive
* and the names created for indirect symbols). If this is for indirect symbols
* then the indr and undef fields are non-zero.
*/
struct indr_object {
char *membername; /* the base name of the object file */
char *indr; /* the name of the indirect symbol */
char *undef; /* the name of the undefined symbol */
enum bool existing_symbol;
uint32_t index;
};
/*
* The ordered list of the indr objects to be created. The objects created for
* indirect symbols are placed in first in the archive in the order the symbol
* names appear in the list file (so to get known order). Then all of the
* original objects from the old archive are placed in the archive preserving
* their order.
*/
#define INITIAL_LIST_SIZE 250
struct list {
struct indr_object **list; /* the order list */
uint32_t used; /* the number used in the list */
uint32_t size; /* the current size of the list */
};
static struct list indr_list;
/*
* The string table maintained by start_string_table(), add_to_string_table()
* and end_string_table();
*/
#define INITIAL_STRING_TABLE_SIZE 40960
static struct {
char *strings;
uint32_t size;
uint32_t index;
} string_table;
struct undef_map {
enum bool old_symbol;
uint32_t index;
struct nlist symbol;
};
static struct undef_map *undef_map;
static char *qsort_strings = NULL;
static struct nlist *qsort_symbols = NULL;
static void usage(
void);
static void process_list(
char *list_filename,
enum bool nflag);
static void translate_input(
struct arch *archs,
uint32_t narchs,
struct arch_flag *arch_flags,
uint32_t narch_flags,
enum bool all_archs,
enum bool nflag);
static void translate_object(
struct arch *arch,
struct member *member,
struct object *object);
static void translate_dylib(
struct arch *arch,
struct object *object);
static int cmp_qsort_undef_map(
const struct undef_map *sym1,
const struct undef_map *sym2);
static int cmp_qsort_toc(
const struct dylib_table_of_contents *toc1,
const struct dylib_table_of_contents *toc2);
static void make_indr_objects(
struct arch *arch);
static void enter_symbol(
char *name,
int32_t type,
char *indr,
struct indr_object *io);
static struct symbol *lookup_symbol(
char *name);
static struct indr_object *enter_object(
char *membername,
char *indr,
char *undef,
struct list *list);
static void start_string_table(
void);
static int32_t add_to_string_table(
char *p);
static void end_string_table(
void);
static void add_list(
struct list *list,
struct indr_object *item);
/* apple_version is created by the libstuff/Makefile */
extern char apple_version[];
char *version = apple_version;
/*
* The indr(l) program takes the following options:
*
* % indr [-n] list_filename input_file output_file
*
* It builds the output file by translating each symbol name listed in
* list file to the same name with and underbar prepended to it in all the
* objects in the input file. Then it if the input file is an archive and the
* -n flag is not specified then it creates an object for each of these
* symbols with an indirect symbol for the symbol name with an underbar and
* adds that to the output archive.
*
* The -n flag is to suppress creating the indirect objects.
*/
int
main(
int argc,
char *argv[],
char *envp[])
{
int i;
uint32_t j;
enum bool no_flags_left;
char *list_filename, *output_file, *input_file;
struct arch_flag *arch_flags;
uint32_t narch_flags;
enum bool all_archs;
enum bool nflag;
struct arch *archs;
uint32_t narchs;
struct stat stat_buf;
progname = argv[0];
arch_flags = NULL;
narch_flags = 0;
all_archs = FALSE;
archs = NULL;
narchs = 0;
list_filenames = NULL;
list_filename = NULL;
input_file = NULL;
output_file = NULL;
nflag = FALSE;
/*
* Parse the flags.
*/
no_flags_left = FALSE;
for(i = 1; i < argc ; i++){
if(argv[i][0] != '-' || no_flags_left){
if(list_filename == NULL && list_filenames == NULL)
list_filename = argv[i];
else if(input_file == NULL)
input_file = argv[i];
else if(output_file == NULL)
output_file = argv[i];
else
usage();
continue;
}
if(argv[i][1] == '\0'){
no_flags_left = TRUE;
continue;
}
if(strcmp(argv[i], "-arch") == 0){
if(list_filenames != NULL)
fatal("can't mix -arch_indr and -arch arguments");
if(i + 1 >= argc){
error("missing argument(s) to %s option", argv[i]);
usage();
}
if(strcmp("all", argv[i+1]) == 0){
all_archs = TRUE;
}
else{
arch_flags = reallocate(arch_flags,
(narch_flags + 1) * sizeof(struct arch_flag));
if(get_arch_from_flag(argv[i+1],
arch_flags + narch_flags) == 0){
error("unknown architecture specification flag: "
"%s %s", argv[i], argv[i+1]);
arch_usage();
usage();
}
for(j = 0; j < narch_flags; j++){
if(arch_flags[j].cputype ==
arch_flags[narch_flags].cputype &&
(arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
(arch_flags[narch_flags].cpusubtype &
~CPU_SUBTYPE_MASK) &&
strcmp(arch_flags[j].name,
arch_flags[narch_flags].name) == 0)
break;
}
if(j == narch_flags)
narch_flags++;
}
i++;
continue;
}
if(strcmp(argv[i], "-arch_indr") == 0){
if(list_filenames == NULL && narch_flags != 0)
fatal("can't mix -arch_indr and -arch arguments");
if(i + 2 >= argc){
error("missing argument(s) to %s option", argv[i]);
usage();
}
arch_flags = reallocate(arch_flags,
(narch_flags + 1) * sizeof(struct arch_flag));
list_filenames = reallocate(list_filenames,
(narch_flags + 1) * sizeof(char *));
if(get_arch_from_flag(argv[i+1],
arch_flags + narch_flags) == 0){
error("unknown architecture specification flag: "
"%s %s %s", argv[i], argv[i+1], argv[i+2]);
arch_usage();
usage();
}
list_filenames[narch_flags] = argv[i+2];
for(j = 0; j < narch_flags; j++){
if(arch_flags[j].cputype ==
arch_flags[narch_flags].cputype &&
(arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
(arch_flags[narch_flags].cpusubtype &
~CPU_SUBTYPE_MASK) &&
strcmp(arch_flags[j].name,
arch_flags[narch_flags].name) == 0)
break;
}
if(j == narch_flags)
narch_flags++;
i += 2;
continue;
}
for(j = 1; argv[i][j] != '\0'; j++){
switch(argv[i][j]){
case 'n':
nflag = TRUE;
break;
default:
error("unknown flag -%c", argv[i][j]);
usage();
}
}
}
if((list_filename == NULL && list_filenames == NULL) ||
input_file == NULL || output_file == NULL)
usage();
/*
* Now do the work.
*/
/* process the list of symbols and create the data structures */
if(list_filenames == NULL)
process_list(list_filename, nflag);
/* breakout the input file for processing */
breakout(input_file, &archs, &narchs, FALSE);
if(errors)
exit(EXIT_FAILURE);
/* checkout the input file for symbol table replacement processing */
checkout(archs, narchs);
/* translate the symbols in the input file */
translate_input(archs, narchs, arch_flags, narch_flags, all_archs,
nflag);
if(errors)
exit(EXIT_FAILURE);
/* create the output file */
if(stat(input_file, &stat_buf) == -1)
system_error("can't stat input file: %s", input_file);
writeout(archs, narchs, output_file, stat_buf.st_mode & 0777, TRUE,
FALSE, FALSE, FALSE, NULL);
if(errors)
return(EXIT_FAILURE);
else
return(EXIT_SUCCESS);
}
/*
* Print the current usage message and exit non-zero.
*/
static
void
usage()
{
fprintf(stderr, "Usage: %s [-n] [[-arch arch_flag] ...] "
"<symbol list file> <input file> <output file>\n", progname);
fprintf(stderr, "Usage: %s [-n] [[-arch_indr arch_flag "
"<symbol list file>] ...] <input file> <output file>\n",
progname);
exit(EXIT_FAILURE);
}
/*
* process the symbols listed in list_filename. This enters each symbol as an
* indirect symbol into the symbol hash table as well as the undefined symbol
* for the indirection. Then it creates the name of the object file that will
* be used to put these symbols in.
*/
static
void
process_list(
char *list_filename,
enum bool nflag)
{
FILE *list;
char buf[BUFSIZ], *symbol_name, *_symbol_name, *membername;
int32_t i, symbol_number;
size_t len;
struct indr_object *io;
/*
* Reset things first.
*/
for(i = 0; i < SYMBOL_HASH_SIZE; i++)
symbol_hash[i] = NULL;
memset(&indr_list, '\0', sizeof(struct list));
if((list = fopen(list_filename, "r")) == NULL)
system_fatal("can't open: %s", list_filename);
io = NULL;
symbol_number = 0;
buf[BUFSIZ-1] = '\0';
while(fgets(buf, BUFSIZ-1, list) != NULL){
len = strlen(buf);
if(buf[len-1] != '\n')
fatal("symbol name: %s too long from file: %s", buf,
list_filename);
buf[len-1] = '\0';
symbol_name = makestr(buf, NULL);
_symbol_name = makestr("_", symbol_name, NULL);
if(nflag == FALSE){
sprintf(buf, "%05d", symbol_number++);
membername = makestr("INDR", buf, ".o", NULL);
io = enter_object(membername, symbol_name, _symbol_name,
&indr_list);
}
enter_symbol(symbol_name, N_INDR, _symbol_name, io);
enter_symbol(_symbol_name, N_UNDF, NULL, io);
}
if(ferror(list))
system_fatal("can't read: %s", list_filename);
fclose(list);
}
/*
* Translate the objects in the input file by changing the external symbols
* that match indirect symbols in the symbol hash table to the symbol that the
* indirect symbol is for.
*/
static
void
translate_input(
struct arch *archs,
uint32_t narchs,
struct arch_flag *arch_flags,
uint32_t narch_flags,
enum bool all_archs,
enum bool nflag)
{
uint32_t i, j, offset, size;
cpu_type_t cputype;
cpu_subtype_t cpusubtype;
struct arch_flag host_arch_flag;
enum bool arch_process, any_processing, *arch_flag_processed;
char *list_filename;
struct ar_hdr h;
char size_buf[sizeof(h.ar_size) + 1];
arch_flag_processed = NULL;
/*
* Using the specified arch_flags process specified objects for those
* architecures.
*/
any_processing = FALSE;
if(narch_flags != 0)
arch_flag_processed = allocate(narch_flags * sizeof(enum bool));
memset(arch_flag_processed, '\0', narch_flags * sizeof(enum bool));
for(i = 0; i < narchs; i++){
/*
* Determine the architecture (cputype and cpusubtype) of arch[i]
*/
cputype = 0;
cpusubtype = 0;
if(archs[i].type == OFILE_ARCHIVE){
for(j = 0; j < archs[i].nmembers; j++){
if(archs[i].members[j].type == OFILE_Mach_O){
cputype = archs[i].members[j].object->mh_cputype;
cpusubtype = archs[i].members[j].object->mh_cpusubtype;
break;
}
}
}
else if(archs[i].type == OFILE_Mach_O){
cputype = archs[i].object->mh_cputype;
cpusubtype = archs[i].object->mh_cpusubtype;
}
else if(archs[i].fat_arch64 != NULL){
cputype = archs[i].fat_arch64->cputype;
cpusubtype = archs[i].fat_arch64->cpusubtype;
}
else if(archs[i].fat_arch != NULL){
cputype = archs[i].fat_arch->cputype;
cpusubtype = archs[i].fat_arch->cpusubtype;
}
arch_process = FALSE;
list_filename = NULL;
if(all_archs == TRUE){
arch_process = TRUE;
}
else if(narch_flags != 0){
for(j = 0; j < narch_flags; j++){
if(arch_flags[j].cputype == cputype &&
(arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
(cpusubtype & ~CPU_SUBTYPE_MASK)){
arch_process = TRUE;
arch_flag_processed[j] = TRUE;
if(list_filenames != NULL)
list_filename = list_filenames[j];
break;
}
}
}
else{
(void)get_arch_from_host(&host_arch_flag, NULL);
if(host_arch_flag.cputype == cputype &&
(host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
(cpusubtype & ~CPU_SUBTYPE_MASK))
arch_process = TRUE;
}
if(narchs != 1 && arch_process == FALSE)
continue;
any_processing = TRUE;
if(list_filename != NULL)
process_list(list_filename, nflag);
/*
* Now this arch[i] has been selected to be processed so process it
* according to it's type.
*/
if(archs[i].type == OFILE_ARCHIVE){
for(j = 0; j < archs[i].nmembers; j++){
if(archs[i].members[j].type == OFILE_Mach_O){
translate_object(archs + i, archs[i].members + j,
archs[i].members[j].object);
}
}
/*
* Make the objects for the indirect symbols in the -n flag is
* not specified since this architecure is an archive.
*/
if(nflag == FALSE)
make_indr_objects(archs + i);
/*
* Reset the library offsets and size.
*/
offset = 0;
for(j = 0; j < archs[i].nmembers; j++){
archs[i].members[j].offset = offset;
size = 0;
if(archs[i].members[j].member_long_name == TRUE){
size = rnd32(archs[i].members[j].member_name_size,
sizeof(int32_t));
archs[i].toc_long_name = TRUE;
}
if(archs[i].members[j].object != NULL){
size += archs[i].members[j].object->object_size
- archs[i].members[j].object->input_sym_info_size
+ archs[i].members[j].object->output_sym_info_size;
sprintf(size_buf, "%-*ld",
(int)sizeof(archs[i].members[j].ar_hdr->ar_size),
(long)(size));
/*
* This has to be done by hand because sprintf puts a
* null at the end of the buffer.
*/
memcpy(archs[i].members[j].ar_hdr->ar_size, size_buf,
(int)sizeof(archs[i].members[j].ar_hdr->ar_size));
}
else{
size += archs[i].members[j].unknown_size;
}
offset += sizeof(struct ar_hdr) + size;
}
archs[i].library_size = offset;
}
else if(archs[i].type == OFILE_Mach_O){
translate_object(archs + i, NULL, archs[i].object);
}
else {
fatal_arch(archs + i, NULL, "can't process non-object and "
"non-archive file: ");
}
}
if(all_archs == FALSE && narch_flags != 0){
for(i = 0; i < narch_flags; i++){
if(arch_flag_processed[i] == FALSE)
error("file: %s does not contain architecture: %s",
archs[0].file_name, arch_flags[i].name);
}
free(arch_flag_processed);
}
if(any_processing == FALSE)
fatal("no processing done on input file: %s (specify a -arch flag)",
archs[0].file_name);
}
/*
* translate the one object's symbols which match the symbols for which indirect
* symbols are to be created.
*/
static
void
translate_object(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t i, j;
enum byte_sex host_byte_sex;
struct nlist *symbols, *nlistp;
uint32_t nsyms, offset;
char *strings;
uint32_t strings_size;
struct symbol *sp;
int32_t new_nsyms;
struct nlist *new_symbols;
if(object->mh_filetype == MH_DYLIB ||
object->mh_filetype == MH_DYLIB_STUB){
if(member != NULL)
fatal_arch(arch, member, "is a dynamic library which is not "
"allowed as a member of an archive");
translate_dylib(arch, object);
return;
}
host_byte_sex = get_host_byte_sex();
if(object->st == NULL || object->st->nsyms == 0)
return;
symbols = (struct nlist *)(object->object_addr + object->st->symoff);
nsyms = object->st->nsyms;
if(object->object_byte_sex != host_byte_sex)
swap_nlist(symbols, nsyms, host_byte_sex);
strings = object->object_addr + object->st->stroff;
strings_size = object->st->strsize;
object->output_symbols = symbols;
object->output_nsymbols = nsyms;
object->input_sym_info_size = nsyms * sizeof(struct nlist) +
object->st->strsize;
if(object->dyst != NULL){
object->input_sym_info_size +=
object->dyst->nindirectsyms * sizeof(uint32_t);
}
/*
* Always clear the prebind checksum if any when creating a new file.
*/
if(object->cs != NULL)
object->cs->cksum = 0;
start_string_table();
nlistp = symbols;
for(i = 0; i < nsyms; i++){
if(nlistp->n_type & N_EXT){
if(nlistp->n_un.n_strx){
if(nlistp->n_un.n_strx > 0 &&
(uint32_t)nlistp->n_un.n_strx < strings_size){
sp = lookup_symbol(strings + nlistp->n_un.n_strx);
if(sp != NULL){
if(sp->type == N_UNDF)
fatal_arch(arch, member, "symbol name: "
"%s conflicts with symbol name created for "
"indirection in: ", sp->name);
nlistp->n_un.n_strx = add_to_string_table(sp->indr);
}
else{
nlistp->n_un.n_strx = add_to_string_table(
strings + nlistp->n_un.n_strx);
}
}
else
fatal_arch(arch, member, "bad string table "
"index in symbol %u in: ", i);
}
}
else{
if(nlistp->n_un.n_strx){
if(nlistp->n_un.n_strx > 0 && nlistp->n_un.n_strx <
(int32_t)strings_size)
nlistp->n_un.n_strx = add_to_string_table(
strings + nlistp->n_un.n_strx);
else
fatal_arch(arch, member, "bad string table "
"index in symbol %u in: ", i);
}
}
nlistp++;
}
/*
* This is a hack to keep the full reference object of a host shared
* library correct when it is processed by this program. To do this
* The name of the object, "__.FVMLIB_REF", is checked for and if this
* is it an undefined symbol for each indirect symbol is added so to
* cause all the indrect objects to be loaded.
*/
new_symbols = NULL;
if(member != NULL &&
strncmp(member->ar_hdr->ar_name, "__.FVMLIB_REF",
sizeof("__.FVMLIB_REF") - 1) == 0){
new_nsyms = 0;
for(i = 0; i < SYMBOL_HASH_SIZE; i++){
sp = symbol_hash[i];
while(sp != NULL){
if(sp->type == N_INDR)
new_nsyms++;
sp = sp->next;
}
}
new_symbols = allocate((nsyms + new_nsyms) * sizeof(struct nlist));
memcpy(new_symbols, symbols, nsyms * sizeof(struct nlist));
j = nsyms;
for(i = 0; i < SYMBOL_HASH_SIZE; i++){
sp = symbol_hash[i];
while(sp != NULL){
if(sp->type == N_INDR){
new_symbols[j].n_un.n_strx =
add_to_string_table(sp->name);
new_symbols[j].n_type = N_UNDF | N_EXT;
new_symbols[j].n_sect = NO_SECT;
new_symbols[j].n_desc = 0;
new_symbols[j].n_value = 0;
j++;
}
sp = sp->next;
}
}
symbols = new_symbols;
object->output_symbols = symbols;
nsyms += new_nsyms;
object->output_nsymbols = nsyms;
}
end_string_table();
object->output_strings = allocate(string_table.index);
memcpy(object->output_strings, string_table.strings,string_table.index);
object->output_strings_size = string_table.index;
object->output_sym_info_size =
nsyms * sizeof(struct nlist) +
string_table.index;
if(object->dyst != NULL){
object->output_sym_info_size +=
object->dyst->nindirectsyms * sizeof(uint32_t);
}
if(object->seg_linkedit != NULL){
object->seg_linkedit->filesize += object->output_sym_info_size -
object->input_sym_info_size;
object->seg_linkedit->vmsize = object->seg_linkedit->filesize;
}
if(object->dyst != NULL){
object->st->nsyms = nsyms;
object->st->strsize = string_table.index;
offset = UINT_MAX;
if(object->st->nsyms != 0 &&
object->st->symoff < offset)
offset = object->st->symoff;
if(object->dyst->nindirectsyms != 0 &&
object->dyst->indirectsymoff < offset)
offset = object->dyst->indirectsymoff;
if(object->st->strsize != 0 &&
object->st->stroff < offset)
offset = object->st->stroff;
if(object->st->nsyms != 0){
object->st->symoff = offset;
offset += object->st->nsyms * sizeof(struct nlist);
}
else
object->st->symoff = 0;
if(object->dyst->nindirectsyms != 0){
object->output_indirect_symtab = (uint32_t *)
(object->object_addr + object->dyst->indirectsymoff);
object->dyst->indirectsymoff = offset;
offset += object->dyst->nindirectsyms *
sizeof(uint32_t);
}
else
object->dyst->indirectsymoff = 0;;
if(object->st->strsize != 0){
object->st->stroff = offset;
offset += object->st->strsize;
}
else
object->st->stroff = 0;
}
else{
object->st->nsyms = nsyms;
object->st->stroff = object->st->symoff +
nsyms * sizeof(struct nlist);
object->st->strsize = string_table.index;
}
}
/*
* translate the dynamic library.
*/
static
void
translate_dylib(
struct arch *arch,
struct object *object)
{
enum byte_sex host_byte_sex;
uint32_t i, inew_syms, inew_undefsyms, inew_mods, indr_iextdefsym;
uint32_t new_ext_strsize, offset;
uint32_t *map;
size_t len;
struct symbol *sp;
char *p, *q;
struct scattered_relocation_info *sreloc;
struct nlist *symbols;
uint32_t nsyms;
char *strings;
uint32_t strsize;
struct dylib_table_of_contents *tocs;
uint32_t ntoc;
struct dylib_module *mods;
uint32_t nmodtab;
struct dylib_reference *refs;
uint32_t nextrefsyms;
struct relocation_info *ext_relocs;
uint32_t *indirect_symtab;
struct nlist *new_symbols;
uint32_t new_nsyms;
char *new_strings;
uint32_t new_strsize;
uint32_t new_nlocalsym;
uint32_t new_nextdefsym;
uint32_t new_nundefsym;
struct dylib_table_of_contents *new_tocs;
uint32_t new_ntoc;
struct dylib_module *new_mods;
uint32_t new_nmodtab;
struct dylib_reference *new_refs;
uint32_t new_nextrefsyms;
/*
* Break out all the old tables.
*/
symbols = (struct nlist *)(object->object_addr + object->st->symoff);
nsyms = object->st->nsyms;
strings = object->object_addr + object->st->stroff;
strsize = object->st->strsize;
tocs = (struct dylib_table_of_contents *)
(object->object_addr + object->dyst->tocoff);
ntoc = object->dyst->ntoc;
mods = (struct dylib_module *)
(object->object_addr + object->dyst->modtaboff);
nmodtab = object->dyst->nmodtab;
refs = (struct dylib_reference *)
(object->object_addr + object->dyst->extrefsymoff);
nextrefsyms = object->dyst->nextrefsyms;
ext_relocs = (struct relocation_info *)
(object->object_addr + object->dyst->extreloff);
indirect_symtab = (uint32_t *)
(object->object_addr + object->dyst->indirectsymoff);
/*
* Swap them if needed.
*/
host_byte_sex = get_host_byte_sex();
if(object->object_byte_sex != host_byte_sex){
swap_nlist(symbols, nsyms, host_byte_sex);
swap_dylib_table_of_contents(tocs, ntoc, host_byte_sex);
swap_dylib_module(mods, nmodtab, host_byte_sex);
swap_dylib_reference(refs, nextrefsyms, host_byte_sex);
swap_relocation_info(ext_relocs, object->dyst->nextrel,
host_byte_sex);
swap_indirect_symbols(indirect_symtab, object->dyst->nindirectsyms,
host_byte_sex);
}
/*
* First pass, figrure out the new sizes of the new tables.
*/
/*
* For the symbol table and string table recalculate the their sizes
* with the names of the symbols listed in the indr file renamed and
* an indirect symbol added.
* Look to make sure no symbols exist that would colide with the
* indirect's undefined symbol names that will be created. This is so
* the symbols can be renamed.
*/
new_nsyms = 0;
new_strsize = sizeof(int32_t);
new_nlocalsym = 0;
new_nextdefsym = 0;
new_nundefsym = 0;
new_ext_strsize = 0;
for(i = 0; i < nsyms; i++){
if(symbols[i].n_un.n_strx != 0){
if((uint32_t)symbols[i].n_un.n_strx > strsize){
error_arch(arch, NULL, "bad string index for symbol "
"table entry %d in: ", i);
return;
}
}
if((symbols[i].n_type & N_TYPE) == N_INDR){
if(symbols[i].n_value != 0){
if(symbols[i].n_value > strsize){
error_arch(arch, NULL, "bad string index for "
"indirect symbol table entry %d in: ", i);
return;
}
}
}
if((symbols[i].n_type & N_EXT) == 0){ /* local symbol */
if(symbols[i].n_un.n_strx != 0)
new_strsize += strlen(strings + symbols[i].n_un.n_strx) + 1;
new_nlocalsym++;
new_nsyms++;
}
else{ /* global symbol */
len = 0;
if(symbols[i].n_un.n_strx != 0){
sp = lookup_symbol(strings + symbols[i].n_un.n_strx);
if(sp != NULL){
if(sp->type == N_UNDF)
fatal_arch(arch, NULL, "symbol name: %s conflicts "
"with symbol name created for indirection in: ",
sp->name);
else{
len = strlen(sp->indr) + 1;
sp->io->existing_symbol = TRUE;
sp->io->index = i;
}
}
else
len = strlen(strings + symbols[i].n_un.n_strx) + 1;
}
if((symbols[i].n_type & N_TYPE) == N_INDR)
len += strlen(strings + symbols[i].n_value) + 1;
new_strsize += len;
new_ext_strsize += len;
new_nsyms++;
if(((symbols[i].n_type & N_TYPE) == N_UNDF &&
symbols[i].n_value == 0) ||
(symbols[i].n_type & N_TYPE) == N_PBUD)
new_nundefsym++;
else
new_nextdefsym++;
}
}
/*
* The new symbol table will have 1 new defined external for each
* indirect symbol name on the indr list. And 1 new undefined symbol
* if the undefined symbol name does not exist.
*/
for(i = 0; i < indr_list.used; i++){
new_nsyms++;
new_nextdefsym++;
/* if there is not an existing symbol there will be a new undef */
if(indr_list.list[i]->existing_symbol == FALSE){
new_nsyms++;
new_nundefsym++;
}
len = strlen(indr_list.list[i]->indr) + 1;
len += strlen(indr_list.list[i]->undef) + 1;
new_strsize += len;
new_ext_strsize += len;
}
/*
* The module table's module names are placed with the external strings.
* So size them and add this to the external string size.
*/
for(i = 0; i < nmodtab; i++){
if(mods[i].module_name == 0 ||
mods[i].module_name > strsize){
error_arch(arch, NULL, "bad string index for module_name "
"of module table entry %d in: ", i);
return;
}
len = strlen(strings + mods[i].module_name) + 1;
new_strsize += len;
new_ext_strsize += len;
}
/*
* A new module will be created for each indr symbol so add the sizes
* of those module names to the external string size.
*/
for(i = 0; i < indr_list.used; i++){
len = strlen(indr_list.list[i]->membername) + 1;
new_strsize += len;
new_ext_strsize += len;
}
/*
* The new module table will have one extra entry for each indr symbol.
*/
new_nmodtab = nmodtab + indr_list.used;
/*
* The new reference table will have two extra entries for each indr
* symbol. One for the definition of the indr and one for the undefined
* that it refers to.
*/
new_nextrefsyms = nextrefsyms + 2 * indr_list.used;
/*
* The new table of contents will have extra entry for each indr symbol.
*/
new_ntoc = ntoc + indr_list.used;
/*
* Second pass, create the new tables.
*/
new_symbols =(struct nlist *)allocate(new_nsyms * sizeof(struct nlist));
new_strsize = rnd32(new_strsize, sizeof(int32_t));
new_strings = (char *)allocate(new_strsize);
new_strings[new_strsize - 3] = '\0';
new_strings[new_strsize - 2] = '\0';
new_strings[new_strsize - 1] = '\0';
memset(new_strings, '\0', sizeof(int32_t));
p = new_strings + sizeof(int32_t);
q = p + new_ext_strsize;
/*
* Now create the new symbol table and string table in this order
* symbol table
* local symbols (sorted by module)
* external defined symbols (sorted by module)
* undefined symbols (sorted by name)
* string table
* external strings
* local strings
*/
map = (uint32_t *)allocate(nsyms * sizeof(uint32_t));
memset(map, '\0', nsyms * sizeof(uint32_t));
inew_syms = 0;
for(i = 0; i < nsyms; i++){ /* loop for local symbols */
if((symbols[i].n_type & N_EXT) == 0){
new_symbols[inew_syms] = symbols[i];
if(symbols[i].n_un.n_strx != 0){
strcpy(q, strings + symbols[i].n_un.n_strx);
new_symbols[inew_syms].n_un.n_strx =
(uint32_t)(q - new_strings);
q += strlen(q) + 1;
}
map[i] = inew_syms;
inew_syms++;
}
}
for(i = 0; i < nsyms; i++){ /* loop for external defined symbols */
if((symbols[i].n_type & N_EXT) == N_EXT &&
((symbols[i].n_type & N_TYPE) != N_UNDF &&
(symbols[i].n_type & N_TYPE) != N_PBUD)){
new_symbols[inew_syms] = symbols[i];
if(symbols[i].n_un.n_strx != 0){
sp = lookup_symbol(strings + symbols[i].n_un.n_strx);
if(sp != NULL)
strcpy(p, sp->indr);
else
strcpy(p, strings + symbols[i].n_un.n_strx);
new_symbols[inew_syms].n_un.n_strx =
(uint32_t)(p - new_strings);
p += strlen(p) + 1;
}
if((symbols[i].n_type & N_TYPE) == N_INDR){
if(symbols[i].n_value != 0){
strcpy(p, strings + symbols[i].n_value);
new_symbols[inew_syms].n_value =
(uint32_t)(p - new_strings);
p += strlen(p) + 1;
}
}
map[i] = inew_syms;
inew_syms++;
}
}
indr_iextdefsym = inew_syms;
for(i = 0; i < indr_list.used; i++){ /* loop for new defined symbols*/
strcpy(p, indr_list.list[i]->indr);
new_symbols[inew_syms].n_un.n_strx = (uint32_t)(p - new_strings);
p += strlen(p) + 1;
new_symbols[inew_syms].n_type = N_INDR | N_EXT;
new_symbols[inew_syms].n_desc = 0;
new_symbols[inew_syms].n_sect = NO_SECT;
/* Note this name is used below for the undefined */
strcpy(p, indr_list.list[i]->undef);
indr_list.list[i]->undef = p;
new_symbols[inew_syms].n_value = (uint32_t)(p - new_strings);
p += strlen(p) + 1;
inew_syms++;
}
/*
* To get the undefined symbols in order sorted by name they are first
* copied into the undef_map, sorted and then copied into the
* new_symbols in the sorted order.
*/
undef_map = (struct undef_map *)allocate(new_nundefsym *
sizeof(struct undef_map));
inew_undefsyms = 0;
for(i = 0; i < indr_list.used; i++){ /* loop for new undef symbols */
if(indr_list.list[i]->existing_symbol == FALSE){
/* Note this name is used from above for the undefined */
undef_map[inew_undefsyms].symbol.n_un.n_strx =
(uint32_t)(indr_list.list[i]->undef - new_strings);
undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT;
undef_map[inew_undefsyms].symbol.n_desc = 0;
undef_map[inew_undefsyms].symbol.n_sect = NO_SECT;
undef_map[inew_undefsyms].symbol.n_value = 0;
undef_map[inew_undefsyms].old_symbol = FALSE;
undef_map[inew_undefsyms].index = i;
inew_undefsyms++;
}
}
for(i = 0; i < nsyms; i++){ /* loop for undefined symbols */
if((symbols[i].n_type & N_EXT) == N_EXT &&
((symbols[i].n_type & N_TYPE) == N_UNDF ||
(symbols[i].n_type & N_TYPE) == N_PBUD)){
undef_map[inew_undefsyms].symbol = symbols[i];
if(symbols[i].n_un.n_strx != 0){
sp = lookup_symbol(strings + symbols[i].n_un.n_strx);
if(sp != NULL)
strcpy(p, sp->indr);
else
strcpy(p, strings + symbols[i].n_un.n_strx);
undef_map[inew_undefsyms].symbol.n_un.n_strx =
(uint32_t)(p - new_strings);
p += strlen(p) + 1;
}
undef_map[inew_undefsyms].old_symbol = TRUE;
undef_map[inew_undefsyms].index = i;
inew_undefsyms++;
}
}
/* Sort the undefined symbols by name */
qsort_strings = new_strings;
qsort(undef_map, new_nundefsym, sizeof(struct undef_map),
(int (*)(const void *, const void *))cmp_qsort_undef_map);
/* Copy the symbols now in sorted order into new_symbols */
for(i = 0; i < new_nundefsym; i++){
new_symbols[inew_syms] = undef_map[i].symbol;
/* update the map for these symbols */
if(undef_map[i].old_symbol == TRUE)
map[undef_map[i].index] = inew_syms;
else
indr_list.list[undef_map[i].index]->index = inew_syms;
inew_syms++;
}
/*
* Fill in the new module table. First copy in the old table, and
* module names. Then add the new module table entries for the
* indr modules.
*/
new_mods = (struct dylib_module *)allocate(
new_nmodtab * sizeof(struct dylib_module));
inew_mods = 0;
for(i = 0; i < nmodtab; i++){
new_mods[inew_mods] = mods[i];
strcpy(p, strings + mods[i].module_name);
new_mods[inew_mods].module_name = (uint32_t)(p - new_strings);
p += strlen(p) + 1;
inew_mods++;
}
for(i = 0; i < indr_list.used; i++){
memset(new_mods + inew_mods, '\0', sizeof(struct dylib_module));
strcpy(p, indr_list.list[i]->membername);
new_mods[inew_mods].module_name = (uint32_t)(p - new_strings);
p += strlen(p) + 1;
new_mods[inew_mods].iextdefsym = indr_iextdefsym + i;
new_mods[inew_mods].nextdefsym = 1;
new_mods[inew_mods].irefsym = nextrefsyms + i * 2;
new_mods[inew_mods].nrefsym = 2;
inew_mods++;
}
/*
* Fill in the new reference table. First copy in the old table. Then
* create entries for the indr modules.
*/
new_refs = (struct dylib_reference *)allocate(
new_nextrefsyms * sizeof(struct dylib_reference));
for(i = 0; i < nextrefsyms; i++){
new_refs[i].isym = map[refs[i].isym];
new_refs[i].flags = refs[i].flags;
}
for(i = 0; i < indr_list.used; i++){
new_refs[nextrefsyms + i*2].isym = indr_iextdefsym + i;
new_refs[nextrefsyms + i*2].flags = REFERENCE_FLAG_DEFINED;
if(indr_list.list[i]->existing_symbol == TRUE)
new_refs[nextrefsyms + i*2 + 1].isym =
map[indr_list.list[i]->index];
else
new_refs[nextrefsyms + i*2 + 1].isym =
indr_list.list[i]->index;
new_refs[nextrefsyms + i*2 + 1].flags =
REFERENCE_FLAG_UNDEFINED_NON_LAZY;
}
/*
* Fill in the new table of contents. First copy in the old table.
* Then create entries for the indr symbols.
*/
new_tocs = (struct dylib_table_of_contents *)allocate(
new_ntoc * sizeof(struct dylib_table_of_contents));
for(i = 0; i < ntoc; i++){
new_tocs[i].symbol_index = map[tocs[i].symbol_index];
new_tocs[i].module_index = tocs[i].module_index;
}
for(i = 0; i < indr_list.used; i++){
new_tocs[ntoc + i].symbol_index = indr_iextdefsym + i;
new_tocs[ntoc + i].module_index = nmodtab + i;
}
qsort_strings = new_strings;
qsort_symbols = new_symbols;
qsort(new_tocs, new_ntoc, sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))cmp_qsort_toc);
/*
* Remap indexes into symbol table in the external relocation entries.
*/
for(i = 0; i < object->dyst->nextrel; i++){
if((ext_relocs[i].r_address & R_SCATTERED) == 0 &&
ext_relocs[i].r_extern == 1){
if(ext_relocs[i].r_symbolnum > nsyms){
fatal_arch(arch, NULL, "bad r_symbolnum for external "
"relocation entry %d in: ", i);
}
ext_relocs[i].r_symbolnum = map[ext_relocs[i].r_symbolnum];
}
else{
fatal_arch(arch, NULL, "bad external relocation entry "
"%d (not external) in: ", i);
}
if((ext_relocs[i].r_address & R_SCATTERED) == 0){
if(reloc_has_pair(object->mh_cputype, ext_relocs[i].r_type))
i++;
}
else{
sreloc = (struct scattered_relocation_info *)ext_relocs + i;
if(reloc_has_pair(object->mh_cputype, sreloc->r_type))
i++;
}
}
/*
* Remap indexes into symbol table in the indirect symbol table.
*/
for(i = 0; i < object->dyst->nindirectsyms; i++){
if(indirect_symtab[i] != INDIRECT_SYMBOL_LOCAL &&
indirect_symtab[i] != INDIRECT_SYMBOL_ABS){
if(indirect_symtab[i] > nsyms)
fatal_arch(arch, NULL, "indirect symbol table entry %d "
"(past the end of the symbol table) in: ", i);
indirect_symtab[i] = map[indirect_symtab[i]];
}
}
/*
* Now that all the new tables have been built and existing table
* updated set the object struct to use them.
*/
object->input_sym_info_size =
object->dyst->nlocrel * sizeof(struct relocation_info) +
object->dyst->nextrel * sizeof(struct relocation_info) +
object->dyst->nindirectsyms * sizeof(uint32_t) +
nsyms * sizeof(struct nlist) +
strsize +
ntoc * sizeof(struct dylib_table_of_contents)+
nmodtab * sizeof(struct dylib_module) +
nextrefsyms * sizeof(struct dylib_reference);
object->output_sym_info_size =
object->dyst->nlocrel * sizeof(struct relocation_info) +
object->dyst->nextrel * sizeof(struct relocation_info) +
object->dyst->nindirectsyms * sizeof(uint32_t) +
new_nsyms * sizeof(struct nlist) +
new_strsize +
new_ntoc * sizeof(struct dylib_table_of_contents)+
new_nmodtab * sizeof(struct dylib_module) +
new_nextrefsyms * sizeof(struct dylib_reference);
if(object->split_info_cmd != NULL){
object->input_sym_info_size += object->split_info_cmd->datasize;
object->output_sym_info_size += object->split_info_cmd->datasize;
}
if(object->func_starts_info_cmd != NULL){
object->input_sym_info_size +=
object->func_starts_info_cmd->datasize;
object->output_sym_info_size +=
object->func_starts_info_cmd->datasize;
}
if(object->data_in_code_cmd != NULL){
object->input_sym_info_size +=
object->data_in_code_cmd->datasize;
object->output_sym_info_size +=
object->data_in_code_cmd->datasize;
}
if(object->code_sign_drs_cmd != NULL){
object->input_sym_info_size +=
object->code_sign_drs_cmd->datasize;
object->output_sym_info_size +=
object->code_sign_drs_cmd->datasize;
}
if(object->link_opt_hint_cmd != NULL){
object->input_sym_info_size +=
object->link_opt_hint_cmd->datasize;
object->output_sym_info_size +=
object->link_opt_hint_cmd->datasize;
}
if(object->hints_cmd != NULL){
object->input_sym_info_size +=
object->hints_cmd->nhints * sizeof(struct twolevel_hint);
object->output_sym_info_size +=
object->hints_cmd->nhints * sizeof(struct twolevel_hint);
}
if(object->code_sig_cmd != NULL){
object->input_sym_info_size =
rnd32(object->input_sym_info_size, 16);
object->input_sym_info_size +=
object->code_sig_cmd->datasize;
object->output_sym_info_size =
rnd32(object->output_sym_info_size, 16);
object->output_sym_info_size +=
object->code_sig_cmd->datasize;
}
if(object->seg_linkedit != NULL){
object->seg_linkedit->filesize += object->output_sym_info_size -
object->input_sym_info_size;
object->seg_linkedit->vmsize = object->seg_linkedit->filesize;
}
object->output_symbols = new_symbols;
object->output_nsymbols = new_nsyms;
object->output_strings = new_strings;
object->output_strings_size = new_strsize;
object->output_tocs = new_tocs;
object->output_ntoc = new_ntoc;
object->output_mods = new_mods;
object->output_nmodtab = new_nmodtab;
object->output_refs = new_refs;
object->output_nextrefsyms = new_nextrefsyms;
object->output_loc_relocs = (struct relocation_info *)
(object->object_addr + object->dyst->locreloff);
if(object->split_info_cmd != NULL){
object->output_split_info_data =
(object->object_addr + object->split_info_cmd->dataoff);
object->output_split_info_data_size =
object->split_info_cmd->datasize;
}
if(object->func_starts_info_cmd != NULL){
object->output_func_start_info_data =
(object->object_addr + object->func_starts_info_cmd->dataoff);
object->output_func_start_info_data_size =
object->func_starts_info_cmd->datasize;
}
if(object->data_in_code_cmd != NULL){
object->output_data_in_code_info_data =
(object->object_addr + object->data_in_code_cmd->dataoff);
object->output_data_in_code_info_data_size =
object->data_in_code_cmd->datasize;
}
if(object->code_sign_drs_cmd != NULL){
object->output_code_sign_drs_info_data =
(object->object_addr + object->code_sign_drs_cmd->dataoff);
object->output_code_sign_drs_info_data_size =
object->code_sign_drs_cmd->datasize;
}
if(object->link_opt_hint_cmd != NULL){
object->output_link_opt_hint_info_data =
(object->object_addr + object->link_opt_hint_cmd->dataoff);
object->output_link_opt_hint_info_data_size =
object->link_opt_hint_cmd->datasize;
}
object->output_ext_relocs = ext_relocs;
object->output_indirect_symtab = indirect_symtab;
if(object->hints_cmd != NULL){
object->output_hints = (struct twolevel_hint *)
(object->object_addr + object->hints_cmd->offset);
}
if(object->code_sig_cmd != NULL){
object->output_code_sig_data = object->object_addr +
object->code_sig_cmd->dataoff;
object->output_code_sig_data_size =
object->code_sig_cmd->datasize;
}
if(object->object_byte_sex != host_byte_sex){
/* the symbol table gets swapped by writeout() */
swap_dylib_table_of_contents(new_tocs, new_ntoc,
object->object_byte_sex);
swap_dylib_module(new_mods, new_nmodtab,
object->object_byte_sex);
swap_dylib_reference(new_refs, new_nextrefsyms,
object->object_byte_sex);
swap_relocation_info(ext_relocs, object->dyst->nextrel,
object->object_byte_sex);
swap_indirect_symbols(indirect_symtab, object->dyst->nindirectsyms,
object->object_byte_sex);
}
object->st->nsyms = new_nsyms;
object->st->strsize = new_strsize;
object->dyst->ilocalsym = 0;
object->dyst->nlocalsym = new_nlocalsym;
object->dyst->iextdefsym = new_nlocalsym;
object->dyst->nextdefsym = new_nextdefsym;
object->dyst->iundefsym = new_nlocalsym + new_nextdefsym;
object->dyst->nundefsym = new_nundefsym;
object->dyst->ntoc = new_ntoc;
object->dyst->nmodtab = new_nmodtab;
object->dyst->nextrefsyms = new_nextrefsyms;
offset = object->seg_linkedit->fileoff;
if(object->dyst->nlocrel != 0){
object->dyst->locreloff = offset;
offset += object->dyst->nlocrel * sizeof(struct relocation_info);
}
if(object->split_info_cmd != NULL){
object->split_info_cmd->dataoff = offset;
offset += object->split_info_cmd->datasize;
}
if(object->func_starts_info_cmd != NULL){
object->func_starts_info_cmd->dataoff = offset;
offset += object->func_starts_info_cmd->datasize;
}
if(object->data_in_code_cmd != NULL){
object->data_in_code_cmd->dataoff = offset;
offset += object->data_in_code_cmd->datasize;
}
if(object->code_sign_drs_cmd != NULL){
object->code_sign_drs_cmd->dataoff = offset;
offset += object->code_sign_drs_cmd->datasize;
}
if(object->link_opt_hint_cmd != NULL){
object->link_opt_hint_cmd->dataoff = offset;
offset += object->link_opt_hint_cmd->datasize;
}
if(object->st->nsyms != 0){
object->st->symoff = offset;
offset += object->st->nsyms * sizeof(struct nlist);
}
if(object->hints_cmd != NULL){
if(object->hints_cmd->nhints != 0){
object->hints_cmd->offset = offset;
offset += object->hints_cmd->nhints *
sizeof(struct twolevel_hint);
}
}
if(object->dyst->nextrel != 0){
object->dyst->extreloff = offset;
offset += object->dyst->nextrel * sizeof(struct relocation_info);
}
if(object->dyst->nindirectsyms != 0){
object->dyst->indirectsymoff = offset;
offset += object->dyst->nindirectsyms * sizeof(uint32_t);
}
if(object->dyst->ntoc != 0){
object->dyst->tocoff = offset;
offset += object->dyst->ntoc *
sizeof(struct dylib_table_of_contents);
}
if(object->dyst->nmodtab != 0){
object->dyst->modtaboff = offset;
offset += object->dyst->nmodtab * sizeof(struct dylib_module);
}
if(object->dyst->nextrefsyms != 0){
object->dyst->extrefsymoff = offset;
offset += object->dyst->nextrefsyms *
sizeof(struct dylib_reference);
}
if(object->st->strsize != 0){
object->st->stroff = offset;
offset += object->st->strsize;
}
if(object->code_sig_cmd != NULL){
offset = rnd32(offset, 16);
object->code_sig_cmd->dataoff = offset;
offset += object->code_sig_cmd->datasize;
}
}
/*
* Function for qsort for comparing undefined map entries.
*/
static
int
cmp_qsort_undef_map(
const struct undef_map *sym1,
const struct undef_map *sym2)
{
return(strcmp(qsort_strings + sym1->symbol.n_un.n_strx,
qsort_strings + sym2->symbol.n_un.n_strx));
}
/*
* Function for qsort for comparing table of contents entries.
*/
static
int
cmp_qsort_toc(
const struct dylib_table_of_contents *toc1,
const struct dylib_table_of_contents *toc2)
{
return(strcmp(
qsort_strings + qsort_symbols[toc1->symbol_index].n_un.n_strx,
qsort_strings + qsort_symbols[toc2->symbol_index].n_un.n_strx));
}
/*
* make_indr_objects writes an object file for each symbol name that was in the
* list file. The object contains an indirect symbol for the symbol_name. The
* symbol name used as the indirect symbol has been constructed by prepending
* an underbar to symbol_name previously in process_list().
*/
static
void
make_indr_objects(
struct arch *arch)
{
int32_t i;
cpu_type_t cputype;
cpu_subtype_t cpusubtype;
enum byte_sex target_byte_sex;
struct indr_object *io;
struct nlist *output_symbols, *undef, *indr;
char *output_strings, *object_addr;
uint32_t object_size;
struct mach_header *mh;
struct symtab_command *st;
struct ar_hdr *ar_hdr;
uint32_t indr_time, size;
unsigned short indr_mode;
int oumask;
gid_t gid;
uid_t uid;
struct object *object;
/*
* Make room for the indr objects in this arch's member list. The
* indr objects will be place first in the list so the exising members
* will be moved to the end of the end of the newly realloced list.
*/
arch->members = reallocate(arch->members,
(arch->nmembers + indr_list.used) *
sizeof(struct member));
cputype = 0;
cpusubtype = 0;
target_byte_sex = UNKNOWN_BYTE_SEX;
for(i = arch->nmembers - 1; i >= 0 ;i--){
if(arch->members[i].object != NULL){
if(cputype == 0){
cputype = arch->members[i].object->mh_cputype;
cpusubtype = arch->members[i].object->mh_cpusubtype;
}
if(target_byte_sex == UNKNOWN_BYTE_SEX){
target_byte_sex = arch->members[i].object->object_byte_sex;
}
}
arch->members[i + indr_list.used] = arch->members[i];
}
memset(arch->members, '\0', indr_list.used * sizeof(struct member));
arch->nmembers += indr_list.used;
if(cputype == 0 || target_byte_sex == UNKNOWN_BYTE_SEX)
fatal_arch(arch, NULL, "can't determine the cputype and/or the "
"byte sex for: ");
/*
* Now loop through the indr list creating the objects for each indirect
* symbol to be added to this archive.
*/
indr_time = (uint32_t)time(0);
oumask = umask(0);
indr_mode = S_IFREG | (0666 & ~oumask);
(void)umask(oumask);
gid = getgid();
uid = getuid();
for(i = 0; i < indr_list.used; i++){
io = indr_list.list[i];
output_symbols = allocate(2 * sizeof(struct nlist));
undef = output_symbols + 0;
indr = output_symbols + 1;
start_string_table();
undef->n_un.n_strx = add_to_string_table(io->undef);
undef->n_type = N_UNDF | N_EXT;
undef->n_sect = NO_SECT;
undef->n_desc = 0;
undef->n_value = 0;
indr->n_un.n_strx = add_to_string_table(io->indr);
indr->n_type = N_INDR | N_EXT;
indr->n_sect = NO_SECT;
indr->n_desc = 0;
indr->n_value = undef->n_un.n_strx;
end_string_table();
output_strings = allocate(string_table.index);
memcpy(output_strings, string_table.strings, string_table.index);
object_size = sizeof(struct mach_header) +
sizeof(struct symtab_command);
object_addr = allocate(object_size);
mh = (struct mach_header *)object_addr;
st = (struct symtab_command *)(object_addr +
sizeof(struct mach_header));
mh->magic = MH_MAGIC;
mh->cputype = cputype;
mh->cpusubtype = cpusubtype;
mh->filetype = MH_OBJECT;
mh->ncmds = 1;
mh->sizeofcmds = sizeof(struct symtab_command);
mh->flags = 0;
st->cmd = LC_SYMTAB;
st->cmdsize = sizeof(struct symtab_command);
st->symoff = sizeof(struct mach_header) +
sizeof(struct symtab_command);
st->nsyms = 2;
st->stroff = sizeof(struct mach_header) +
sizeof(struct symtab_command) +
2 * sizeof(struct nlist);
st->strsize = string_table.index;
size = sizeof(struct mach_header) +
sizeof(struct symtab_command) +
2 * sizeof(struct nlist) +
string_table.index;
arch->members[i].type = OFILE_Mach_O;
ar_hdr = allocate(sizeof(struct ar_hdr) + 1);
arch->members[i].ar_hdr = ar_hdr;
sprintf((char *)ar_hdr, "%-*s%-*ld%-*u%-*u%-*o%-*ld%-*s",
(int)sizeof(ar_hdr->ar_name),
io->membername,
(int)sizeof(ar_hdr->ar_date),
(long)indr_time,
(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)indr_mode,
(int)sizeof(ar_hdr->ar_size),
(long)(size),
(int)sizeof(ar_hdr->ar_fmag),
ARFMAG);
object = allocate(sizeof(struct object));
memset(object, '\0', sizeof(struct object));
arch->members[i].object = object;
object->object_addr = object_addr;
object->object_size = object_size;
object->object_byte_sex = target_byte_sex;
object->mh = mh;
object->load_commands = (struct load_command *)st;
object->st = NULL;
object->input_sym_info_size = 0;
object->output_sym_info_size = 2 * sizeof(struct nlist) +
string_table.index;
object->output_symbols = output_symbols;
object->output_nsymbols = 2;
object->output_strings = output_strings;
object->output_strings_size = string_table.index;
arch->members[i].input_file_name = arch->file_name;
arch->members[i].input_ar_hdr = ar_hdr;
}
}
/*
* enter a symbol and it's type into the symbol hash table checking for
* duplicates. Duplicates cause a fatal error to be printed.
*/
static
void
enter_symbol(
char *name,
int32_t type,
char *indr,
struct indr_object *io)
{
int32_t hash_key;
struct symbol *sp;
hash_key = hash_string(name) % SYMBOL_HASH_SIZE;
sp = symbol_hash[hash_key];
while(sp != NULL){
if(strcmp(name, sp->name) == 0){
fatal("to create %s symbol: %s would conflict with also to be "
"created %s symbol: %s",
type == N_INDR ? "indirect" : "undefined", name,
sp->type == N_INDR ? "indirect" : "undefined", sp->name);
}
sp = sp->next;
}
sp = (struct symbol *)allocate(sizeof(struct symbol));
sp->name = name;
sp->type = type;
sp->indr = indr;
sp->io = io;
sp->next = symbol_hash[hash_key];
symbol_hash[hash_key] = sp;
}
/*
* lookup a symbol name in the symbol hash table returning a pointer to the
* symbol structure for it. A NULL pointer is returned if not found.
*/
static
struct symbol *
lookup_symbol(
char *name)
{
int32_t hash_key;
struct symbol *sp;
hash_key = hash_string(name) % SYMBOL_HASH_SIZE;
sp = symbol_hash[hash_key];
while(sp != NULL){
if(strcmp(name, sp->name) == 0){
return(sp);
}
sp = sp->next;
}
return(NULL);
}
/*
* Create and enter an indr object and it's informaton into the specified list.
*/
static
struct indr_object *
enter_object(
char *membername,
char *indr,
char *undef,
struct list *list)
{
struct indr_object *io;
io = allocate(sizeof(struct indr_object));
io->membername = membername;
io->indr = indr;
io->undef = undef;
io->existing_symbol = FALSE;
io->index = 0;
add_list(list, io);
return(io);
}
/*
* This routine is called before calls to add_to_string_table() are made to
* setup or reset the string table structure. The first four bytes string
* table are zeroed and the first string is placed after that (this was for
* the string table length in a 4.3bsd a.out along time ago). The first four
* bytes are kept zero even thought only the first byte can't be used as valid
* string offset (because that is defined to be a NULL string) but to avoid
* breaking programs that don't know this the first byte is left zero and the
* first 4 bytes are not stuffed with the size because on a little endian
* machine that first byte is likely to be non-zero.
*/
static
void
start_string_table()
{
if(string_table.size == 0){
string_table.size = INITIAL_STRING_TABLE_SIZE;
string_table.strings = (char *)allocate(string_table.size);
}
memset(string_table.strings, '\0', sizeof(int32_t));
string_table.index = sizeof(int32_t);
}
/*
* This routine adds the specified string to the string table structure and
* returns the index of the string in the table.
*/
static
int32_t
add_to_string_table(
char *p)
{
size_t len;
uint32_t index;
len = strlen(p) + 1;
if(string_table.size < string_table.index + len){
string_table.strings = (char *)reallocate(string_table.strings,
string_table.size * 2);
string_table.size *= 2;
}
index = string_table.index;
strcpy(string_table.strings + string_table.index, p);
string_table.index += len;
return(index);
}
/*
* This routine is called after all calls to add_to_string_table() are made
* to round off the size of the string table. It zeros the rounded bytes.
*/
static
void
end_string_table()
{
uint32_t length;
length = rnd32(string_table.index, sizeof(uint32_t));
memset(string_table.strings + string_table.index, '\0',
length - string_table.index);
string_table.index = length;
}
/*
* Add the item to the specified list. Lists can be reused just by setting
* list->used to zero. The item after the last item is allways set to NULL
* so that list->list can be used for things like execv() calls directly.
*/
static
void
add_list(
struct list *list,
struct indr_object *item)
{
if(list->used + 1 >= list->size){
if(list->size == 0){
list->list = allocate(INITIAL_LIST_SIZE * sizeof(void *));
list->size = INITIAL_LIST_SIZE;
list->used = 0;
}
else{
list->list = reallocate(list->list,
list->size * 2 * sizeof(void *));
list->size *= 2;
}
}
list->list[list->used++] = item;
list->list[list->used] = NULL;
}