#ifndef RLD
#include <sys/time.h>
#include <mach/mach.h>
#include "stuff/openstep_mach.h"
#include <libc.h>
#ifndef __OPENSTEP__
#include <utime.h>
#endif
#include "stuff/ofile.h"
#include "stuff/breakout.h"
#include "stuff/allocate.h"
#include "stuff/rnd.h"
#include "stuff/errors.h"
static void copy_new_symbol_info(
char *p,
uint32_t *size,
struct dysymtab_command *dyst,
struct dysymtab_command *old_dyst,
struct twolevel_hints_command *hints_cmd,
struct twolevel_hints_command *old_hints_cmd,
struct object *object);
static void make_table_of_contents(
struct arch *archs,
char *output,
time_t toc_time,
enum bool sort_toc,
enum bool commons_in_toc,
enum bool library_warnings);
static enum bool toc_symbol(
struct nlist *symbol,
enum bool commons_in_toc,
struct section **sections);
static enum bool toc_symbol_64(
struct nlist_64 *symbol64,
enum bool commons_in_toc,
struct section_64 **sections64);
static enum bool toc(
uint32_t n_strx,
uint8_t n_type,
uint64_t n_value,
enum bool commons_in_toc,
enum bool attr_no_toc);
static int toc_entry_name_qsort(
const struct toc_entry *toc1,
const struct toc_entry *toc2);
static int toc_entry_index_qsort(
const struct toc_entry *toc1,
const struct toc_entry *toc2);
static enum bool check_sort_toc_entries(
struct arch *arch,
char *output,
enum bool library_warnings);
static void warn_member(
struct arch *arch,
struct member *member,
const char *format, ...)
#ifndef __MWERKS__
__attribute__ ((format (printf, 3, 4)))
#endif
;
__private_extern__
void
writeout(
struct arch *archs,
uint32_t narchs,
char *output,
unsigned short mode,
enum bool sort_toc,
enum bool commons_in_toc,
enum bool library_warnings,
uint32_t *throttle)
{
uint32_t fsync;
int fd;
#ifndef __OPENSTEP__
struct utimbuf timep;
#else
time_t timep[2];
#endif
mach_port_t my_mach_host_self;
char *file, *p;
uint32_t file_size;
time_t toc_time;
enum bool seen_archive;
kern_return_t r;
seen_archive = FALSE;
toc_time = time(0);
writeout_to_mem(archs, narchs, output, (void **)&file, &file_size,
sort_toc, commons_in_toc, library_warnings,
&seen_archive);
(void)unlink(output);
if(throttle != NULL)
fsync = O_FSYNC;
else
fsync = 0;
if(output != NULL){
if((fd = open(output, O_WRONLY|O_CREAT|O_TRUNC|fsync, mode)) == -1){
system_error("can't create output file: %s", output);
goto cleanup;
}
#ifdef F_NOCACHE
(void)fcntl(fd, F_NOCACHE, 1);
#endif
}
else{
throttle = NULL;
fd = fileno(stdout);
}
if(throttle != NULL){
#define WRITE_SIZE (32 * 1024)
struct timeval start, end;
struct timezone tz;
uint32_t bytes_written, bytes_per_second, write_size;
double time_used, time_should_have_took, usecs_to_kill;
static struct host_sched_info info = { 0 };
unsigned int count;
kern_return_t r;
p = file;
bytes_written = 0;
bytes_per_second = 0;
count = HOST_SCHED_INFO_COUNT;
my_mach_host_self = mach_host_self();
if((r = host_info(my_mach_host_self, HOST_SCHED_INFO, (host_info_t)
(&info), &count)) != KERN_SUCCESS){
mach_port_deallocate(mach_task_self(), my_mach_host_self);
my_mach_error(r, "can't get host sched info");
}
mach_port_deallocate(mach_task_self(), my_mach_host_self);
if(gettimeofday(&start, &tz) == -1)
goto no_throttle;
#undef THROTTLE_DEBUG
do {
if((file + file_size) - p < WRITE_SIZE)
write_size = (file + file_size) - p;
else
write_size = WRITE_SIZE;
if(write(fd, p, write_size) != (int)write_size){
system_error("can't write output file: %s", output);
goto cleanup;
}
p += write_size;
if(p < file + file_size || *throttle == UINT_MAX){
bytes_written += write_size;
(void)gettimeofday(&end, &tz);
#ifdef THROTTLE_DEBUG
printf("start sec = %u usec = %u\n", start.tv_sec,
start.tv_usec);
printf("end sec = %u usec = %u\n", end.tv_sec,
end.tv_usec);
#endif
time_used = end.tv_sec - start.tv_sec;
if(end.tv_usec >= start.tv_usec)
time_used +=
((double)(end.tv_usec - start.tv_usec)) / 1000000.0;
else
time_used += -1.0 +
((double)(1000000 + end.tv_usec - start.tv_usec) /
1000000.0);
bytes_per_second = ((double)bytes_written / time_used);
#ifdef THROTTLE_DEBUG
printf("time_used = %f bytes_written = %lu bytes_per_second"
" = %lu throttle = %lu\n", time_used, bytes_written,
bytes_per_second, *throttle);
#endif
if(bytes_per_second > *throttle){
time_should_have_took =
(double)bytes_written * (1.0/(double)(*throttle));
usecs_to_kill =
(time_should_have_took - time_used) * 1000000.0;
#ifdef THROTTLE_DEBUG
printf("time should have taken = %f usecs to kill %f\n",
time_should_have_took, usecs_to_kill);
#endif
usleep((u_int)usecs_to_kill);
bytes_written = 0;
bytes_per_second = 0;
(void)gettimeofday(&start, &tz);
}
}
} while(p < file + file_size);
if(*throttle == UINT_MAX)
*throttle = bytes_per_second;
}
else{
no_throttle:
if(write(fd, file, file_size) != (int)file_size){
system_error("can't write output file: %s", output);
goto cleanup;
}
}
if(output != NULL && close(fd) == -1){
system_fatal("can't close output file: %s", output);
goto cleanup;
}
if(seen_archive == TRUE){
#ifndef __OPENSTEP__
timep.actime = toc_time - 5;
timep.modtime = toc_time - 5;
if(utime(output, &timep) == -1)
#else
timep[0] = toc_time - 5;
timep[1] = toc_time - 5;
if(utime(output, timep) == -1)
#endif
{
system_fatal("can't set the modifiy times in output file: %s",
output);
goto cleanup;
}
}
cleanup:
if((r = vm_deallocate(mach_task_self(), (vm_address_t)file,
file_size)) != KERN_SUCCESS){
my_mach_error(r, "can't vm_deallocate() buffer for output file");
return;
}
}
__private_extern__
void
writeout_to_mem(
struct arch *archs,
uint32_t narchs,
char *filename,
void **outputbuf,
uint32_t *length,
enum bool sort_toc,
enum bool commons_in_toc,
enum bool library_warnings,
enum bool *seen_archive)
{
uint32_t i, j, k, file_size, offset, pad, size;
uint32_t i32;
enum byte_sex target_byte_sex, host_byte_sex;
char *file, *p;
kern_return_t r;
struct fat_header *fat_header;
struct fat_arch *fat_arch;
struct dysymtab_command dyst;
struct twolevel_hints_command hints_cmd;
struct load_command lc, *lcp;
struct dylib_command dl, *dlp;
time_t toc_time;
int32_t timestamp, index;
uint32_t ncmds;
enum bool swapped;
if(filename == NULL)
filename = "(file written out to memory)";
*seen_archive = FALSE;
toc_time = time(0);
fat_arch = NULL;
fat_header = NULL;
if(narchs == 0){
error("no contents for file: %s (not created)", filename);
return;
}
host_byte_sex = get_host_byte_sex();
if(narchs > 1 || archs[0].fat_arch != NULL)
file_size = sizeof(struct fat_header) +
sizeof(struct fat_arch) * narchs;
else
file_size = 0;
for(i = 0; i < narchs; i++){
if(archs[i].type == OFILE_ARCHIVE){
*seen_archive = TRUE;
make_table_of_contents(archs + i, filename, toc_time, sort_toc,
commons_in_toc, library_warnings);
archs[i].library_size += SARMAG + archs[i].toc_size;
if(archs[i].fat_arch != NULL)
file_size = rnd(file_size, 1 << archs[i].fat_arch->align);
file_size += archs[i].library_size;
if(archs[i].fat_arch != NULL)
archs[i].fat_arch->size = archs[i].library_size;
}
else if(archs[i].type == OFILE_Mach_O){
size = archs[i].object->object_size
- archs[i].object->input_sym_info_size
+ archs[i].object->output_new_content_size
+ archs[i].object->output_sym_info_size;
if(archs[i].fat_arch != NULL)
file_size = rnd(file_size, 1 << archs[i].fat_arch->align);
file_size += size;
if(archs[i].fat_arch != NULL)
archs[i].fat_arch->size = size;
}
else{
if(archs[i].fat_arch != NULL)
file_size = rnd(file_size, 1 << archs[i].fat_arch->align);
file_size += archs[i].unknown_size;
if(archs[i].fat_arch != NULL)
archs[i].fat_arch->size = archs[i].unknown_size;
}
}
if((r = vm_allocate(mach_task_self(), (vm_address_t *)&file,
file_size, TRUE)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_allocate() buffer for output file: %s of "
"size %u", filename, file_size);
if(narchs > 1 || archs[0].fat_arch != NULL){
fat_header = (struct fat_header *)file;
fat_header->magic = FAT_MAGIC;
fat_header->nfat_arch = narchs;
offset = sizeof(struct fat_header) +
sizeof(struct fat_arch) * narchs;
fat_arch = (struct fat_arch *)(file + sizeof(struct fat_header));
for(i = 0; i < narchs; i++){
fat_arch[i].cputype = archs[i].fat_arch->cputype;
fat_arch[i].cpusubtype = archs[i].fat_arch->cpusubtype;
offset = rnd(offset, 1 << archs[i].fat_arch->align);
fat_arch[i].offset = offset;
fat_arch[i].size = archs[i].fat_arch->size;
fat_arch[i].align = archs[i].fat_arch->align;
offset += archs[i].fat_arch->size;
}
}
for(i = 0; i < narchs; i++){
if(archs[i].fat_arch != NULL)
p = file + fat_arch[i].offset;
else
p = file;
if(archs[i].type == OFILE_ARCHIVE){
*seen_archive = TRUE;
memcpy(p, ARMAG, SARMAG);
p += SARMAG;
if(library_warnings == TRUE && archs[i].ntocs == 0){
if(narchs > 1 || archs[i].fat_arch != NULL)
warning("warning library: %s for architecture: %s the "
"table of contents is empty (no object file "
"members in the library)", filename,
archs[i].fat_arch_name);
else
warning("warning for library: %s the table of contents "
"is empty (no object file members in the "
"library)", filename);
}
target_byte_sex = UNKNOWN_BYTE_SEX;
for(j = 0;
j < archs[i].nmembers && target_byte_sex ==UNKNOWN_BYTE_SEX;
j++){
if(archs[i].members[j].type == OFILE_Mach_O)
target_byte_sex =
archs[i].members[j].object->object_byte_sex;
}
if(target_byte_sex == UNKNOWN_BYTE_SEX)
target_byte_sex = host_byte_sex;
memcpy(p, (char *)(&archs[i].toc_ar_hdr),sizeof(struct ar_hdr));
p += sizeof(struct ar_hdr);
if(archs[i].toc_long_name == TRUE){
memcpy(p, archs[i].toc_name, archs[i].toc_name_size);
p += archs[i].toc_name_size +
(rnd(sizeof(struct ar_hdr), 8) -
sizeof(struct ar_hdr));
}
i32 = archs[i].ntocs * sizeof(struct ranlib);
if(target_byte_sex != host_byte_sex)
i32 = SWAP_INT(i32);
memcpy(p, (char *)&i32, sizeof(uint32_t));
p += sizeof(uint32_t);
if(target_byte_sex != host_byte_sex)
swap_ranlib(archs[i].toc_ranlibs, archs[i].ntocs,
target_byte_sex);
memcpy(p, (char *)archs[i].toc_ranlibs,
archs[i].ntocs * sizeof(struct ranlib));
p += archs[i].ntocs * sizeof(struct ranlib);
i32 = archs[i].toc_strsize;
if(target_byte_sex != host_byte_sex)
i32 = SWAP_INT(i32);
memcpy(p, (char *)&i32, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, (char *)archs[i].toc_strings, archs[i].toc_strsize);
p += archs[i].toc_strsize;
for(j = 0; j < archs[i].nmembers; j++){
memcpy(p, (char *)(archs[i].members[j].ar_hdr),
sizeof(struct ar_hdr));
p += sizeof(struct ar_hdr);
if(archs[i].members[j].member_long_name == TRUE){
memcpy(p, archs[i].members[j].member_name,
archs[i].members[j].member_name_size);
p += rnd(archs[i].members[j].member_name_size, 8) +
(rnd(sizeof(struct ar_hdr), 8) -
sizeof(struct ar_hdr));
}
if(archs[i].members[j].type == OFILE_Mach_O){
memset(&dyst, '\0', sizeof(struct dysymtab_command));
if(archs[i].members[j].object->dyst != NULL)
dyst = *(archs[i].members[j].object->dyst);
if(archs[i].members[j].object->hints_cmd != NULL)
hints_cmd = *(archs[i].members[j].object->hints_cmd);
if(archs[i].members[j].object->object_byte_sex !=
host_byte_sex){
if(archs[i].members[j].object->mh != NULL){
if(swap_object_headers(
archs[i].members[j].object->mh,
archs[i].members[j].object->load_commands)
== FALSE)
fatal("internal error: "
"swap_object_headers() failed");
if(archs[i].members[j].object->output_nsymbols
!= 0)
swap_nlist(
archs[i].members[j].object->
output_symbols,
archs[i].members[j].object->
output_nsymbols,
archs[i].members[j].object->
object_byte_sex);
}
else{
if(swap_object_headers(
archs[i].members[j].object->mh64,
archs[i].members[j].object->load_commands)
== FALSE)
fatal("internal error: "
"swap_object_headers() failed");
if(archs[i].members[j].object->output_nsymbols
!= 0)
swap_nlist_64(
archs[i].members[j].object->
output_symbols64,
archs[i].members[j].object->
output_nsymbols,
archs[i].members[j].object->
object_byte_sex);
}
}
if(archs[i].members[j].object->
output_sym_info_size == 0 &&
archs[i].members[j].object->
input_sym_info_size == 0){
size = archs[i].members[j].object->object_size;
memcpy(p, archs[i].members[j].object->object_addr,
size);
}
else{
size = archs[i].members[j].object->object_size
- archs[i].members[j].object->
input_sym_info_size;
memcpy(p, archs[i].members[j].object->object_addr,
size);
copy_new_symbol_info(p, &size, &dyst,
archs[i].members[j].object->dyst, &hints_cmd,
archs[i].members[j].object->hints_cmd,
archs[i].members[j].object);
}
p += size;
pad = rnd(size, 8) - size;
}
else{
memcpy(p, archs[i].members[j].unknown_addr,
archs[i].members[j].unknown_size);
p += archs[i].members[j].unknown_size;
pad = rnd(archs[i].members[j].unknown_size, 8) -
archs[i].members[j].unknown_size;
}
for(k = 0; k < pad; k++)
*p++ = '\n';
}
}
else if(archs[i].type == OFILE_Mach_O){
memset(&dyst, '\0', sizeof(struct dysymtab_command));
if(archs[i].object->dyst != NULL)
dyst = *(archs[i].object->dyst);
if(archs[i].object->hints_cmd != NULL)
hints_cmd = *(archs[i].object->hints_cmd);
if(archs[i].object->mh_filetype == MH_DYLIB){
timestamp = 0;
for(index = i - 1; timestamp == 0 && index >= 0; index--){
if(archs[index].type == OFILE_Mach_O &&
archs[index].object->mh_filetype == MH_DYLIB &&
archs[index].object->mh_cputype ==
archs[i].object->mh_cputype){
if(archs[index].object->mh != NULL)
ncmds = archs[index].object->mh->ncmds;
else
ncmds = archs[index].object->mh64->ncmds;
lcp = archs[index].object->load_commands;
swapped = archs[index].object->object_byte_sex !=
host_byte_sex;
if(swapped)
ncmds = SWAP_INT(ncmds);
for(j = 0; j < ncmds; j++){
lc = *lcp;
if(swapped)
swap_load_command(&lc, host_byte_sex);
if(lc.cmd == LC_ID_DYLIB){
dlp = (struct dylib_command *)lcp;
dl = *dlp;
if(swapped)
swap_dylib_command(&dl, host_byte_sex);
timestamp = dl.dylib.timestamp - 1;
break;
}
lcp = (struct load_command *)
((char *)lcp + lc.cmdsize);
}
}
}
if(timestamp == 0)
timestamp = toc_time;
lcp = archs[i].object->load_commands;
if(archs[i].object->mh != NULL)
ncmds = archs[i].object->mh->ncmds;
else
ncmds = archs[i].object->mh64->ncmds;
for(j = 0; j < ncmds; j++){
if(lcp->cmd == LC_ID_DYLIB){
dlp = (struct dylib_command *)lcp;
if(archs[i].dont_update_LC_ID_DYLIB_timestamp ==
FALSE)
dlp->dylib.timestamp = timestamp;
break;
}
lcp = (struct load_command *)((char *)lcp +
lcp->cmdsize);
}
}
if(archs[i].object->object_byte_sex != host_byte_sex){
if(archs[i].object->mh != NULL){
if(swap_object_headers(archs[i].object->mh,
archs[i].object->load_commands) == FALSE)
fatal("internal error: swap_object_headers() "
"failed");
if(archs[i].object->output_nsymbols != 0)
swap_nlist(archs[i].object->output_symbols,
archs[i].object->output_nsymbols,
archs[i].object->object_byte_sex);
}
else{
if(swap_object_headers(archs[i].object->mh64,
archs[i].object->load_commands) == FALSE)
fatal("internal error: swap_object_headers() "
"failed");
if(archs[i].object->output_nsymbols != 0)
swap_nlist_64(archs[i].object->output_symbols64,
archs[i].object->output_nsymbols,
archs[i].object->object_byte_sex);
}
}
if(archs[i].object->output_sym_info_size == 0 &&
archs[i].object->input_sym_info_size == 0){
size = archs[i].object->object_size;
memcpy(p, archs[i].object->object_addr, size);
}
else{
size = archs[i].object->object_size
- archs[i].object->input_sym_info_size;
memcpy(p, archs[i].object->object_addr, size);
if(archs[i].object->output_new_content_size != 0){
memcpy(p + size, archs[i].object->output_new_content,
archs[i].object->output_new_content_size);
size += archs[i].object->output_new_content_size;
}
copy_new_symbol_info(p, &size, &dyst,
archs[i].object->dyst, &hints_cmd,
archs[i].object->hints_cmd,
archs[i].object);
}
}
else{
memcpy(p, archs[i].unknown_addr, archs[i].unknown_size);
}
}
#ifdef __LITTLE_ENDIAN__
if(narchs > 1 || archs[0].fat_arch != NULL){
swap_fat_header(fat_header, BIG_ENDIAN_BYTE_SEX);
swap_fat_arch(fat_arch, narchs, BIG_ENDIAN_BYTE_SEX);
}
#endif
*outputbuf = file;
*length = file_size;
}
static
void
copy_new_symbol_info(
char *p,
uint32_t *size,
struct dysymtab_command *dyst,
struct dysymtab_command *old_dyst,
struct twolevel_hints_command *hints_cmd,
struct twolevel_hints_command *old_hints_cmd,
struct object *object)
{
if(old_dyst != NULL){
if(object->output_dyld_info_size != 0){
if(object->output_dyld_info != NULL)
memcpy(p + *size, object->output_dyld_info,
object->output_dyld_info_size);
*size += object->output_dyld_info_size;
}
memcpy(p + *size, object->output_loc_relocs,
dyst->nlocrel * sizeof(struct relocation_info));
*size += dyst->nlocrel *
sizeof(struct relocation_info);
if(object->output_split_info_data_size != 0){
if(object->output_split_info_data != NULL)
memcpy(p + *size, object->output_split_info_data,
object->output_split_info_data_size);
*size += object->output_split_info_data_size;
}
if(object->output_func_start_info_data_size != 0){
if(object->output_func_start_info_data != NULL)
memcpy(p + *size, object->output_func_start_info_data,
object->output_func_start_info_data_size);
*size += object->output_func_start_info_data_size;
}
if(object->mh != NULL){
memcpy(p + *size, object->output_symbols,
object->output_nsymbols * sizeof(struct nlist));
*size += object->output_nsymbols *
sizeof(struct nlist);
}
else{
memcpy(p + *size, object->output_symbols64,
object->output_nsymbols * sizeof(struct nlist_64));
*size += object->output_nsymbols *
sizeof(struct nlist_64);
}
if(old_hints_cmd != NULL){
memcpy(p + *size, object->output_hints,
hints_cmd->nhints * sizeof(struct twolevel_hint));
*size += hints_cmd->nhints *
sizeof(struct twolevel_hint);
}
memcpy(p + *size, object->output_ext_relocs,
dyst->nextrel * sizeof(struct relocation_info));
*size += dyst->nextrel *
sizeof(struct relocation_info);
memcpy(p + *size, object->output_indirect_symtab,
dyst->nindirectsyms * sizeof(uint32_t));
*size += dyst->nindirectsyms * sizeof(uint32_t) +
object->input_indirectsym_pad;
memcpy(p + *size, object->output_tocs,
object->output_ntoc *sizeof(struct dylib_table_of_contents));
*size += object->output_ntoc *
sizeof(struct dylib_table_of_contents);
if(object->mh != NULL){
memcpy(p + *size, object->output_mods,
object->output_nmodtab * sizeof(struct dylib_module));
*size += object->output_nmodtab *
sizeof(struct dylib_module);
}
else{
memcpy(p + *size, object->output_mods64,
object->output_nmodtab * sizeof(struct dylib_module_64));
*size += object->output_nmodtab *
sizeof(struct dylib_module_64);
}
memcpy(p + *size, object->output_refs,
object->output_nextrefsyms * sizeof(struct dylib_reference));
*size += object->output_nextrefsyms *
sizeof(struct dylib_reference);
memcpy(p + *size, object->output_strings,
object->output_strings_size);
*size += object->output_strings_size;
if(object->output_code_sig_data_size != 0){
*size = rnd(*size, 16);
if(object->output_code_sig_data != NULL)
memcpy(p + *size, object->output_code_sig_data,
object->output_code_sig_data_size);
*size += object->output_code_sig_data_size;
}
}
else{
if(object->mh != NULL){
memcpy(p + *size, object->output_symbols,
object->output_nsymbols * sizeof(struct nlist));
*size += object->output_nsymbols *
sizeof(struct nlist);
}
else{
memcpy(p + *size, object->output_symbols64,
object->output_nsymbols * sizeof(struct nlist_64));
*size += object->output_nsymbols *
sizeof(struct nlist_64);
}
memcpy(p + *size, object->output_strings,
object->output_strings_size);
*size += object->output_strings_size;
if(object->output_code_sig_data_size != 0){
*size = rnd(*size, 16);
if(object->output_code_sig_data != NULL)
memcpy(p + *size, object->output_code_sig_data,
object->output_code_sig_data_size);
*size += object->output_code_sig_data_size;
}
}
}
static
void
make_table_of_contents(
struct arch *arch,
char *output,
time_t toc_time,
enum bool sort_toc,
enum bool commons_in_toc,
enum bool library_warnings)
{
uint32_t i, j, k, r, s, nsects;
struct member *member;
struct object *object;
struct load_command *lc;
struct segment_command *sg;
struct segment_command_64 *sg64;
struct nlist *symbols;
struct nlist_64 *symbols64;
uint32_t nsymbols;
char *strings;
uint32_t strings_size;
enum bool sorted;
unsigned short toc_mode;
int oumask, numask;
char *ar_name;
struct section *section;
struct section_64 *section64;
uint32_t ncmds;
symbols = NULL;
symbols64 = NULL;
strings = NULL;
for(i = 0; i < arch->nmembers; i++){
member = arch->members + i;
if(member->type == OFILE_Mach_O){
object = member->object;
nsymbols = 0;
nsects = 0;
lc = object->load_commands;
if(object->mh != NULL)
ncmds = object->mh->ncmds;
else
ncmds = object->mh64->ncmds;
for(j = 0; j < ncmds; j++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
nsects += sg->nsects;
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
nsects += sg64->nsects;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(object->mh != NULL){
object->sections = allocate(nsects *
sizeof(struct section *));
object->sections64 = NULL;
}
else{
object->sections = NULL;
object->sections64 = allocate(nsects *
sizeof(struct section_64 *));
}
nsects = 0;
lc = object->load_commands;
for(j = 0; j < ncmds; j++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
section = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(k = 0; k < sg->nsects; k++){
object->sections[nsects++] = section++;
}
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
section64 = (struct section_64 *)
((char *)sg64 + sizeof(struct segment_command_64));
for(k = 0; k < sg64->nsects; k++){
object->sections64[nsects++] = section64++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(object->output_sym_info_size == 0){
lc = object->load_commands;
for(j = 0; j < ncmds; j++){
if(lc->cmd == LC_SYMTAB){
object->st = (struct symtab_command *)lc;
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(object->st != NULL && object->st->nsyms != 0){
if(object->mh != NULL){
symbols = (struct nlist *)(object->object_addr +
object->st->symoff);
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist(symbols, object->st->nsyms,
get_host_byte_sex());
}
else{
symbols64 = (struct nlist_64 *)
(object->object_addr + object->st->symoff);
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist_64(symbols64, object->st->nsyms,
get_host_byte_sex());
}
nsymbols = object->st->nsyms;
strings = object->object_addr + object->st->stroff;
strings_size = object->st->strsize;
}
}
else {
if(object->mh != NULL)
symbols = object->output_symbols;
else
symbols64 = object->output_symbols64;
nsymbols = object->output_nsymbols;
strings = object->output_strings;
strings_size = object->output_strings_size;
}
for(j = 0; j < nsymbols; j++){
if(object->mh != NULL){
if(toc_symbol(symbols + j, commons_in_toc,
object->sections) == TRUE){
arch->ntocs++;
arch->toc_strsize +=
strlen(strings + symbols[j].n_un.n_strx) + 1;
}
}
else{
if(toc_symbol_64(symbols64 + j, commons_in_toc,
object->sections64) == TRUE){
arch->ntocs++;
arch->toc_strsize +=
strlen(strings + symbols64[j].n_un.n_strx) + 1;
}
}
}
}
}
arch->toc_entries = allocate(sizeof(struct toc_entry) * arch->ntocs);
arch->toc_ranlibs = allocate(sizeof(struct ranlib) * arch->ntocs);
arch->toc_strsize = rnd(arch->toc_strsize, 8);
arch->toc_strings = allocate(arch->toc_strsize);
r = 0;
s = 0;
for(i = 0; i < arch->nmembers; i++){
member = arch->members + i;
if(member->type == OFILE_Mach_O){
object = member->object;
nsymbols = 0;
if(object->output_sym_info_size == 0){
if(object->st != NULL){
if(object->mh != NULL)
symbols = (struct nlist *)
(object->object_addr + object->st->symoff);
else
symbols64 = (struct nlist_64 *)
(object->object_addr + object->st->symoff);
nsymbols = object->st->nsyms;
strings = object->object_addr + object->st->stroff;
strings_size = object->st->strsize;
}
else{
symbols = NULL;
nsymbols = 0;
strings = NULL;
strings_size = 0;
}
}
else{
if(object->mh != NULL)
symbols = object->output_symbols;
else
symbols64 = object->output_symbols64;
nsymbols = object->output_nsymbols;
strings = object->output_strings;
strings_size = object->output_strings_size;
}
for(j = 0; j < nsymbols; j++){
if(object->mh != NULL){
if((uint32_t)symbols[j].n_un.n_strx > strings_size)
continue;
if(toc_symbol(symbols + j, commons_in_toc,
object->sections) == TRUE){
strcpy(arch->toc_strings + s,
strings + symbols[j].n_un.n_strx);
arch->toc_entries[r].symbol_name =
arch->toc_strings + s;
arch->toc_entries[r].member_index = i + 1;
r++;
s += strlen(strings + symbols[j].n_un.n_strx) + 1;
}
}
else{
if((uint32_t)symbols64[j].n_un.n_strx >
strings_size)
continue;
if(toc_symbol_64(symbols64 + j, commons_in_toc,
object->sections64) == TRUE){
strcpy(arch->toc_strings + s,
strings + symbols64[j].n_un.n_strx);
arch->toc_entries[r].symbol_name =
arch->toc_strings + s;
arch->toc_entries[r].member_index = i + 1;
r++;
s += strlen(strings + symbols64[j].n_un.n_strx) + 1;
}
}
}
if(object->output_sym_info_size == 0){
if(object->object_byte_sex != get_host_byte_sex()){
if(object->mh != NULL)
swap_nlist(symbols, nsymbols,
object->object_byte_sex);
else
swap_nlist_64(symbols64, nsymbols,
object->object_byte_sex);
}
}
}
}
if(sort_toc == TRUE){
qsort(arch->toc_entries, arch->ntocs, sizeof(struct toc_entry),
(int (*)(const void *, const void *))toc_entry_name_qsort);
sorted = check_sort_toc_entries(arch, output, library_warnings);
if(sorted == FALSE){
qsort(arch->toc_entries, arch->ntocs, sizeof(struct toc_entry),
(int (*)(const void *, const void *))
toc_entry_index_qsort);
}
}
else{
sorted = FALSE;
}
if(arch->toc_long_name == FALSE)
fatal("internal error: make_table_of_contents() called with "
"arch->toc_long_name == FALSE");
if(sorted == TRUE){
ar_name = AR_EFMT1 "20";
arch->toc_name_size = sizeof(SYMDEF_SORTED) - 1;
arch->toc_name = SYMDEF_SORTED;
}
else{
ar_name = AR_EFMT1 "20";
arch->toc_name_size = 16;
arch->toc_name = SYMDEF "\0\0\0\0\0\0\0";
}
arch->toc_size = sizeof(struct ar_hdr) +
sizeof(uint32_t) +
arch->ntocs * sizeof(struct ranlib) +
sizeof(uint32_t) +
arch->toc_strsize;
if(arch->toc_long_name == TRUE)
arch->toc_size += arch->toc_name_size +
(rnd(sizeof(struct ar_hdr), 8) -
sizeof(struct ar_hdr));
for(i = 0; i < arch->nmembers; i++)
arch->members[i].offset += SARMAG + arch->toc_size;
for(i = 0; i < arch->ntocs; i++){
arch->toc_ranlibs[i].ran_un.ran_strx =
arch->toc_entries[i].symbol_name - arch->toc_strings;
arch->toc_ranlibs[i].ran_off =
arch->members[arch->toc_entries[i].member_index - 1].offset;
}
numask = 0;
oumask = umask(numask);
toc_mode = S_IFREG | (0666 & ~oumask);
(void)umask(oumask);
sprintf((char *)(&arch->toc_ar_hdr), "%-*s%-*ld%-*u%-*u%-*o%-*ld",
(int)sizeof(arch->toc_ar_hdr.ar_name),
ar_name,
(int)sizeof(arch->toc_ar_hdr.ar_date),
toc_time,
(int)sizeof(arch->toc_ar_hdr.ar_uid),
(unsigned short)getuid(),
(int)sizeof(arch->toc_ar_hdr.ar_gid),
(unsigned short)getgid(),
(int)sizeof(arch->toc_ar_hdr.ar_mode),
(unsigned int)toc_mode,
(int)sizeof(arch->toc_ar_hdr.ar_size),
(long)(arch->toc_size - sizeof(struct ar_hdr)));
memcpy(arch->toc_ar_hdr.ar_fmag, ARFMAG,
(int)sizeof(arch->toc_ar_hdr.ar_fmag));
}
static
enum bool
toc_symbol(
struct nlist *symbol,
enum bool commons_in_toc,
struct section **sections)
{
return(toc(symbol->n_un.n_strx,
symbol->n_type,
symbol->n_value,
commons_in_toc,
(symbol->n_type & N_TYPE) == N_SECT &&
sections[symbol->n_sect - 1]->flags & S_ATTR_NO_TOC));
}
static
enum bool
toc_symbol_64(
struct nlist_64 *symbol64,
enum bool commons_in_toc,
struct section_64 **sections64)
{
return(toc(symbol64->n_un.n_strx,
symbol64->n_type,
symbol64->n_value,
commons_in_toc,
(symbol64->n_type & N_TYPE) == N_SECT &&
sections64[symbol64->n_sect-1]->flags & S_ATTR_NO_TOC));
}
static
enum bool
toc(
uint32_t n_strx,
uint8_t n_type,
uint64_t n_value,
enum bool commons_in_toc,
enum bool attr_no_toc)
{
if(n_strx == 0)
return(FALSE);
if((n_type & N_EXT) == 0)
return(FALSE);
if((n_type & N_TYPE) == N_UNDF && n_value == 0)
return(FALSE);
if((n_type & N_TYPE) == N_UNDF && n_value != 0 &&
commons_in_toc == FALSE)
return(FALSE);
if(attr_no_toc != 0)
return(FALSE);
return(TRUE);
}
static
int
toc_entry_name_qsort(
const struct toc_entry *toc1,
const struct toc_entry *toc2)
{
return(strcmp(toc1->symbol_name, toc2->symbol_name));
}
static
int
toc_entry_index_qsort(
const struct toc_entry *toc1,
const struct toc_entry *toc2)
{
if(toc1->member_index < toc2->member_index)
return(-1);
if(toc1->member_index > toc2->member_index)
return(1);
return(0);
}
static
enum bool
check_sort_toc_entries(
struct arch *arch,
char *output,
enum bool library_warnings)
{
uint32_t i;
enum bool multiple_defs;
struct member *member;
if(arch->ntocs == 0 || arch->ntocs == 1)
return(TRUE);
multiple_defs = FALSE;
for(i = 0; i < arch->ntocs - 1; i++){
if(strcmp(arch->toc_entries[i].symbol_name,
arch->toc_entries[i+1].symbol_name) == 0){
if(multiple_defs == FALSE){
if(library_warnings == FALSE)
return(FALSE);
fprintf(stderr, "%s: same symbol defined in more than one "
"member ", progname);
if(arch->fat_arch != NULL)
fprintf(stderr, "for architecture: %s ",
arch->fat_arch_name);
fprintf(stderr, "in: %s (table of contents will not be "
"sorted)\n", output);
multiple_defs = TRUE;
}
if(arch->toc_entries[i].member_index > 0){
member = arch->members +
arch->toc_entries[i].member_index - 1;
warn_member(arch, member, "defines symbol: %s",
arch->toc_entries[i].symbol_name);
arch->toc_entries[i].member_index =
-(arch->toc_entries[i].member_index);
}
if(arch->toc_entries[i+1].member_index > 0){
member = arch->members +
arch->toc_entries[i+1].member_index - 1;
warn_member(arch, member, "defines symbol: %s",
arch->toc_entries[i+1].symbol_name);
arch->toc_entries[i+1].member_index =
-(arch->toc_entries[i+1].member_index);
}
}
}
if(multiple_defs == FALSE)
return(TRUE);
else{
for(i = 0; i < arch->ntocs; i++)
if(arch->toc_entries[i].member_index < 0)
arch->toc_entries[i].member_index =
-(arch->toc_entries[i].member_index);
return(FALSE);
}
}
static
void
warn_member(
struct arch *arch,
struct member *member,
const char *format, ...)
{
va_list ap;
fprintf(stderr, "%s: ", progname);
if(arch->fat_arch != NULL)
fprintf(stderr, "for architecture: %s ", arch->fat_arch_name);
if(member->input_ar_hdr != NULL){
fprintf(stderr, "file: %s(%.*s) ", member->input_file_name,
(int)member->member_name_size, member->member_name);
}
else
fprintf(stderr, "file: %s ", member->input_file_name);
va_start(ap, format);
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
va_end(ap);
}
#endif