#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libc.h>
#include "stuff/bool.h"
#include "stuff/errors.h"
#include "stuff/breakout.h"
#include "stuff/allocate.h"
#include "stuff/rnd.h"
#include "stuff/execute.h"
char *progname = NULL;
static enum bool rflag = FALSE;
static enum bool mflag = FALSE;
static enum bool lflag = FALSE;
static enum bool vflag = FALSE;
static enum bool some_slice_has_bitcode = FALSE;
static void usage(
void);
static void process(
struct arch *archs,
uint32_t narchs);
static enum bool check_object(
struct arch *arch,
struct member *member,
struct object *object);
static void strip_bitcode_segment(
struct arch *arch,
struct member *member,
struct object *object);
static void leave_just_bitcode_segment(
struct arch *arch,
struct member *member,
struct object *object);
static void strip_bitcode_from_load_commands(
struct arch *arch,
struct object *object);
static void leave_only_bitcode_load_commands(
struct arch *arch,
struct object *object,
enum bool keeping_plist);
static void reset_pointers_for_object_load_commands(
struct arch *arch,
struct object *object);
static void make_ld_process_mh_object(
struct arch *arch,
struct member *member,
struct object *object);
static void make_ld_r_object(
struct arch *arch,
struct object *object);
static void setup_symbolic_info_for_mh_object(
struct arch *arch,
struct member *member,
struct object *object);
int
main(
int argc,
char **argv,
char **envp)
{
uint32_t i;
char *input, *output;
struct arch *archs;
uint32_t narchs;
progname = argv[0];
input = NULL;
output = NULL;
archs = NULL;
narchs = 0;
for(i = 1; i < argc; i++){
if(strcmp(argv[i], "-o") == 0){
if(i + 1 == argc){
error("missing argument(s) to: %s option", argv[i]);
usage();
}
if(output != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
output = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-l") == 0){
if(rflag == TRUE || mflag == TRUE){
error("only one of -r, -m or -l can be specified");
usage();
}
lflag = TRUE;
}
else if(strcmp(argv[i], "-r") == 0){
if(lflag == TRUE || mflag == TRUE){
error("only one of -r, -m or -l can be specified");
usage();
}
rflag = TRUE;
}
else if(strcmp(argv[i], "-m") == 0){
if(lflag == TRUE || rflag == TRUE){
error("only one of -r, -m or -l can be specified");
usage();
}
mflag = TRUE;
}
else if(strcmp(argv[i], "-v") == 0){
vflag = TRUE;
}
else{
if(input != NULL){
error("more than one input file specified (%s and %s)",
argv[i], input);
usage();
}
input = argv[i];
}
}
if(rflag == FALSE && mflag == FALSE && lflag == FALSE){
error("one of -r, -m or -l must specified");
usage();
}
if(input == NULL || output == NULL)
usage();
breakout(input, &archs, &narchs, FALSE);
if(errors)
exit(EXIT_FAILURE);
checkout(archs, narchs);
process(archs, narchs);
if(rflag && some_slice_has_bitcode == FALSE){
if(strcmp(input, output) == 0)
return(EXIT_SUCCESS);
reset_execute_list();
add_execute_list("/bin/cp");
add_execute_list(input);
add_execute_list(output);
if(execute_list(vflag) == 0)
fatal("internal /bin/cp command failed");
return(EXIT_SUCCESS);
}
writeout(archs, narchs, output, 0777, TRUE, FALSE, FALSE, FALSE, NULL);
if(errors)
return(EXIT_FAILURE);
else
return(EXIT_SUCCESS);
}
static
void
usage(
void)
{
fprintf(stderr, "Usage: %s input [-r | -m | -l] -o output\n", progname);
exit(EXIT_FAILURE);
}
static
void
process(
struct arch *archs,
uint32_t narchs)
{
uint32_t i;
uint32_t j, offset, size;
struct object *object;
struct ar_hdr h;
char size_buf[sizeof(h.ar_size) + 1];
for(i = 0; i < narchs; i++){
if(archs[i].type == OFILE_ARCHIVE){
for(j = 0; j < archs[i].nmembers; j++){
if(archs[i].members[j].type == OFILE_Mach_O){
object = archs[i].members[j].object;
if(check_object(archs + i, archs[i].members + j,
object) == FALSE)
return;
if(rflag || mflag ||
(object->mh_filetype != MH_OBJECT &&
object->seg_bitcode == NULL &&
object->seg_bitcode64 == NULL))
strip_bitcode_segment(archs + i,
archs[i].members + j, object);
else
leave_just_bitcode_segment(archs + i,
archs[i].members + j,
object);
}
}
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 = rnd(archs[i].members[j].member_name_size,
sizeof(int64_t));
size = rnd(archs[i].members[j].member_name_size, 8) +
(rnd(sizeof(struct ar_hdr), 8) -
sizeof(struct ar_hdr));
archs[i].toc_long_name = TRUE;
}
if(archs[i].members[j].object != NULL){
size +=
rnd(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,
8);
sprintf(size_buf, "%-*ld",
(int)sizeof(archs[i].members[j].ar_hdr->ar_size),
(long)(size));
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){
object = archs[i].object;
if(check_object(archs + i, NULL, object) == FALSE)
return;
if(rflag || mflag ||
(object->mh_filetype != MH_OBJECT &&
object->seg_bitcode == NULL &&
object->seg_bitcode64 == NULL))
strip_bitcode_segment(archs + i, NULL, object);
else
leave_just_bitcode_segment(archs + i, NULL, object);
}
}
}
static
enum bool
check_object(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t i, mh_ncmds, mh_flags;
struct load_command *lc;
struct segment_command *sg;
struct segment_command_64 *sg64;
uint32_t section_ordinal, first_bitcode_section_ordinal,
last_bitcode_section_ordinal;
struct nlist *symbols;
struct nlist_64 *symbols64;
struct section *s;
struct section_64 *s64;
if(object->mh != NULL){
mh_ncmds = object->mh->ncmds;
mh_flags = object->mh->flags;
}
else{
mh_ncmds = object->mh64->ncmds;
mh_flags = object->mh64->flags;
}
if(object->mh_filetype != MH_OBJECT &&
(mh_flags & MH_DYLDLINK) != MH_DYLDLINK)
fatal_arch(arch, member, "can't be used on a file not built for "
"use with the dynamic linker: ");
if(object->seg_bitcode != NULL || object->seg_bitcode64 != NULL){
section_ordinal = 1;
first_bitcode_section_ordinal = 0;
lc = object->load_commands;
for(i = 0; i < mh_ncmds && first_bitcode_section_ordinal == 0; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(sg == object->seg_bitcode && sg->nsects > 0){
first_bitcode_section_ordinal = section_ordinal;
last_bitcode_section_ordinal = section_ordinal +
sg->nsects;
}
section_ordinal += sg->nsects;
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
if(sg64 == object->seg_bitcode64 && sg64->nsects > 0){
first_bitcode_section_ordinal = section_ordinal;
last_bitcode_section_ordinal = section_ordinal +
sg64->nsects;
}
section_ordinal += sg64->nsects;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(first_bitcode_section_ordinal != 0){
if(object->seg_bitcode != NULL){
symbols = (struct nlist *)
(object->object_addr + object->st->symoff);
for(i = 0; i < object->st->nsyms; i++){
if((symbols[i].n_type & N_TYPE) == N_SECT &&
symbols[i].n_sect >= first_bitcode_section_ordinal &&
symbols[i].n_sect < last_bitcode_section_ordinal){
fatal_arch(arch, member, "bitcode segment can't "
"have symbols defined it its sections in: ");
}
}
}
else{
symbols64 = (struct nlist_64 *)
(object->object_addr + object->st->symoff);
for(i = 0; i < object->st->nsyms; i++){
if((symbols64[i].n_type & N_TYPE) == N_SECT &&
symbols64[i].n_sect >=
first_bitcode_section_ordinal &&
symbols64[i].n_sect < last_bitcode_section_ordinal){
fatal_arch(arch, member, "bitcode segment can't "
"have symbols defined it its sections in: ");
}
}
}
}
}
if(object->seg_bitcode != NULL){
s = (struct section *)((char *)object->seg_bitcode +
sizeof(struct segment_command));
for(i = 0; i < object->seg_bitcode->nsects; i++){
if((s->flags & SECTION_TYPE) != S_REGULAR)
fatal_arch(arch, member, "bitcode segment can't have "
"sections that are not of type S_REGULAR in: ");
s++;
}
}
else if(object->seg_bitcode64 != NULL){
s64 = (struct section_64 *)((char *)object->seg_bitcode64 +
sizeof(struct segment_command_64));
for(i = 0; i < object->seg_bitcode64->nsects; i++){
if((s64->flags & SECTION_TYPE) != S_REGULAR)
fatal_arch(arch, member, "bitcode segment can't have "
"sections that are not of type S_REGULAR in: ");
s64++;
}
}
#if 0
if(lflag == TRUE &&
object->seg_bitcode == NULL && object->seg_bitcode64 == NULL)
fatal_arch(arch, member, "-l to leave only bitcode segment can't "
"be used on a file without a __LLVM segment: ");
#endif
return(TRUE);
}
static
void
strip_bitcode_segment(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t start_offset, offset, end_of_string_table, alignment_padding;
uint32_t dyld_info_start;
uint32_t dyld_info_end;
enum bool has_bitcode;
const struct arch_flag *arch_flag;
uint32_t i, segalign, bitcode_marker_size, sect_offset;
struct section *s;
struct section_64 *s64;
if(object->mh_filetype == MH_OBJECT){
make_ld_process_mh_object(arch, member, object);
return;
}
if(mflag){
arch_flag = get_arch_family_from_cputype(object->mh_cputype);
if(arch_flag != NULL)
segalign = get_segalign_from_flag(arch_flag);
else
segalign = 0x4000;
}
has_bitcode = FALSE;
if(object->mh != NULL){
if(object->seg_bitcode) {
has_bitcode = TRUE;
object->object_size -= object->seg_bitcode->filesize;
object->seg_linkedit->fileoff -= object->seg_bitcode->filesize;
}
object->input_sym_info_size = object->seg_linkedit->filesize;
start_offset = object->seg_linkedit->fileoff;
if(has_bitcode && mflag){
if(object->seg_bitcode->filesize >= segalign)
bitcode_marker_size = segalign;
else
bitcode_marker_size = object->seg_bitcode->filesize;
object->output_new_content = allocate(bitcode_marker_size);
memset(object->output_new_content, '\0', bitcode_marker_size);
object->output_new_content_size = bitcode_marker_size;
object->seg_bitcode->filesize = bitcode_marker_size;
object->seg_bitcode->fileoff = start_offset;
sect_offset = object->seg_bitcode->fileoff;
s = (struct section *)((char *)object->seg_bitcode +
sizeof(struct segment_command));
if(object->seg_bitcode->nsects > 0){
s->offset = sect_offset;
s->size = bitcode_marker_size > 0 ? 1 : 0;
s++;
}
for(i = 1; i < object->seg_bitcode->nsects; i++){
s->offset = 0;
s->size = 0;
s++;
}
object->seg_linkedit->fileoff += object->seg_bitcode->filesize;
start_offset += object->seg_bitcode->filesize;
}
if(has_bitcode && rflag)
object->seg_linkedit->vmaddr = object->seg_bitcode->vmaddr;
}
else{
if(object->seg_bitcode64 != NULL){
has_bitcode = TRUE;
object->object_size -= object->seg_bitcode64->filesize;
object->seg_linkedit64->fileoff -=
object->seg_bitcode64->filesize;
}
object->input_sym_info_size = object->seg_linkedit64->filesize;
start_offset = object->seg_linkedit64->fileoff;
if(has_bitcode && mflag){
if(object->seg_bitcode64->filesize >= segalign)
bitcode_marker_size = segalign;
else
bitcode_marker_size = object->seg_bitcode64->filesize;
object->output_new_content = allocate(bitcode_marker_size);
memset(object->output_new_content, '\0', bitcode_marker_size);
object->output_new_content_size = bitcode_marker_size;
object->seg_bitcode64->filesize = bitcode_marker_size;
object->seg_bitcode64->fileoff = start_offset;
sect_offset = object->seg_bitcode64->fileoff;
s64 = (struct section_64 *)((char *)object->seg_bitcode64 +
sizeof(struct segment_command_64));
if(object->seg_bitcode64->nsects > 0){
s64->offset = sect_offset;
s64->size = bitcode_marker_size > 0 ? 1 : 0;
s64++;
}
for(i = 1; i < object->seg_bitcode64->nsects; i++){
s64->offset = 0;
s64->size = 0;
s64++;
}
object->seg_linkedit64->fileoff +=
object->seg_bitcode64->filesize;
start_offset += object->seg_bitcode64->filesize;
}
if(has_bitcode && rflag)
object->seg_linkedit64->vmaddr = object->seg_bitcode64->vmaddr;
}
if(has_bitcode)
some_slice_has_bitcode = TRUE;
offset = start_offset;
if(object->dyld_info != NULL){
dyld_info_start = 0;
if (object->dyld_info->rebase_off != 0)
dyld_info_start = object->dyld_info->rebase_off;
else if (object->dyld_info->bind_off != 0)
dyld_info_start = object->dyld_info->bind_off;
else if (object->dyld_info->weak_bind_off != 0)
dyld_info_start = object->dyld_info->weak_bind_off;
else if (object->dyld_info->lazy_bind_off != 0)
dyld_info_start = object->dyld_info->lazy_bind_off;
else if (object->dyld_info->export_off != 0)
dyld_info_start = object->dyld_info->export_off;
dyld_info_end = 0;
if (object->dyld_info->export_size != 0)
dyld_info_end = object->dyld_info->export_off
+ object->dyld_info->export_size;
else if (object->dyld_info->lazy_bind_size != 0)
dyld_info_end = object->dyld_info->lazy_bind_off
+ object->dyld_info->lazy_bind_size;
else if (object->dyld_info->weak_bind_size != 0)
dyld_info_end = object->dyld_info->weak_bind_off
+ object->dyld_info->weak_bind_size;
else if (object->dyld_info->bind_size != 0)
dyld_info_end = object->dyld_info->bind_off
+ object->dyld_info->bind_size;
else if (object->dyld_info->rebase_size != 0)
dyld_info_end = object->dyld_info->rebase_off
+ object->dyld_info->rebase_size;
object->output_dyld_info = object->object_addr + dyld_info_start;
object->output_dyld_info_size = dyld_info_end - dyld_info_start;
if(object->dyld_info->rebase_off != 0){
object->dyld_info->rebase_off = offset;
offset += object->dyld_info->rebase_size;
}
if(object->dyld_info->bind_off != 0){
object->dyld_info->bind_off = offset;
offset += object->dyld_info->bind_size;
}
if(object->dyld_info->weak_bind_off != 0){
object->dyld_info->weak_bind_off = offset;
offset += object->dyld_info->weak_bind_size;
}
if(object->dyld_info->lazy_bind_off != 0){
object->dyld_info->lazy_bind_off = offset;
offset += object->dyld_info->lazy_bind_size;
}
if(object->dyld_info->export_off != 0){
object->dyld_info->export_off = offset;
offset += object->dyld_info->export_size;
}
}
if(object->dyst != NULL){
if(object->dyst->nlocrel != 0){
object->output_loc_relocs = (struct relocation_info *)
(object->object_addr + object->dyst->locreloff);
object->dyst->locreloff = offset;
offset +=
object->dyst->nlocrel * sizeof(struct relocation_info);
}
else
object->dyst->locreloff = 0;
}
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;
object->split_info_cmd->dataoff = offset;
offset += 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;
object->func_starts_info_cmd->dataoff = offset;
offset += 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;
object->data_in_code_cmd->dataoff = offset;
offset += object->data_in_code_cmd->datasize;
}
if(object->code_sign_drs_cmd != NULL){
if(has_bitcode){
if(object->mh != NULL)
object->seg_linkedit->filesize -=
object->code_sign_drs_cmd->datasize;
else
object->seg_linkedit64->filesize -=
object->code_sign_drs_cmd->datasize;
object->output_code_sign_drs_info_data = NULL;
object->output_code_sign_drs_info_data_size = 0;
object->code_sign_drs_cmd->dataoff = 0;
object->code_sign_drs_cmd->datasize = 0;
}
else{
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;
object->code_sign_drs_cmd->dataoff = offset;
offset += 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->link_opt_hint_cmd->dataoff = offset;
offset += object->link_opt_hint_cmd->datasize;
}
if(object->st != NULL && object->st->nsyms != 0){
if(object->mh != NULL){
object->output_symbols = (struct nlist *)
(object->object_addr + object->st->symoff);
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist(object->output_symbols,
object->st->nsyms,
get_host_byte_sex());
object->output_symbols64 = NULL;
}
else{
object->output_symbols64 = (struct nlist_64 *)
(object->object_addr + object->st->symoff);
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist_64(object->output_symbols64,
object->st->nsyms,
get_host_byte_sex());
object->output_symbols = NULL;
}
object->output_nsymbols = object->st->nsyms;
object->st->symoff = offset;
if(object->mh != NULL)
offset += object->st->nsyms * sizeof(struct nlist);
else
offset += object->st->nsyms * sizeof(struct nlist_64);
}
else if(object->st != NULL && object->st->nsyms == 0)
object->st->symoff = 0;
if(object->hints_cmd != NULL){
if(object->hints_cmd->nhints != 0){
object->output_hints = (struct twolevel_hint *)
(object->object_addr + object->hints_cmd->offset);
object->hints_cmd->offset = offset;
offset += object->hints_cmd->nhints *
sizeof(struct twolevel_hint);
}
else
object->hints_cmd->offset = 0;
}
if(object->dyst != NULL){
object->output_ilocalsym = object->dyst->ilocalsym;
object->output_nlocalsym = object->dyst->nlocalsym;
object->output_iextdefsym = object->dyst->iextdefsym;
object->output_nextdefsym = object->dyst->nextdefsym;
object->output_iundefsym = object->dyst->iundefsym;
object->output_nundefsym = object->dyst->nundefsym;
if(object->dyst->nextrel != 0){
object->output_ext_relocs = (struct relocation_info *)
(object->object_addr + object->dyst->extreloff);
object->dyst->extreloff = offset;
offset += object->dyst->nextrel *
sizeof(struct relocation_info);
}
else
object->dyst->extreloff = 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) +
object->input_indirectsym_pad;
}
else
object->dyst->indirectsymoff = 0;
if(object->dyst->ntoc != 0){
object->output_tocs =
(struct dylib_table_of_contents *)
(object->object_addr + object->dyst->tocoff);
object->output_ntoc = object->dyst->ntoc;
object->dyst->tocoff = offset;
offset += object->dyst->ntoc *
sizeof(struct dylib_table_of_contents);
}
else
object->dyst->tocoff = 0;
if(object->dyst->nmodtab != 0){
if(object->mh != NULL){
object->output_mods = (struct dylib_module *)
(object->object_addr + object->dyst->modtaboff);
object->output_mods64 = NULL;
}
else{
object->output_mods64 = (struct dylib_module_64 *)
(object->object_addr + object->dyst->modtaboff);
object->output_mods = NULL;
}
object->output_nmodtab = object->dyst->nmodtab;
object->dyst->modtaboff = offset;
if(object->mh != NULL)
offset += object->dyst->nmodtab *
sizeof(struct dylib_module);
else
offset += object->dyst->nmodtab *
sizeof(struct dylib_module_64);
}
else
object->dyst->modtaboff = 0;
if(object->dyst->nextrefsyms != 0){
object->output_refs = (struct dylib_reference *)
(object->object_addr + object->dyst->extrefsymoff);
object->output_nextrefsyms = object->dyst->nextrefsyms;
object->dyst->extrefsymoff = offset;
offset += object->dyst->nextrefsyms *
sizeof(struct dylib_reference);
}
else
object->dyst->extrefsymoff = 0;
}
if(object->st != NULL && object->st->strsize != 0){
end_of_string_table = object->st->stroff + object->st->strsize;
object->output_strings = object->object_addr + object->st->stroff;
object->output_strings_size = object->st->strsize;
object->st->stroff = offset;
offset += object->st->strsize;
}
else{
end_of_string_table = 0;
object->st->stroff = 0;
}
if(object->code_sig_cmd != NULL){
if(has_bitcode){
if(end_of_string_table != 0)
alignment_padding = object->code_sig_cmd->dataoff -
end_of_string_table;
else
alignment_padding = 0;
if(object->mh != NULL)
object->seg_linkedit->filesize -=
object->code_sig_cmd->datasize + alignment_padding;
else
object->seg_linkedit64->filesize -=
object->code_sig_cmd->datasize + alignment_padding;
object->output_code_sig_data = NULL;
object->output_code_sig_data_size = 0;
}
else{
object->output_code_sig_data = object->object_addr +
object->code_sig_cmd->dataoff;
object->output_code_sig_data_size =
object->code_sig_cmd->datasize;
offset = rnd(offset, 16);
object->code_sig_cmd->dataoff = offset;
offset += object->code_sig_cmd->datasize;
}
}
object->output_sym_info_size = offset - start_offset;
if(has_bitcode)
strip_bitcode_from_load_commands(arch, object);
}
static char fake_string_table[8];
static
void
leave_just_bitcode_segment(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t i, j, start_offset, offset, sect_offset;
struct load_command *lc;
struct segment_command *sg, *text;
struct segment_command_64 *sg64, *text64;
struct section *s, *plist;
struct section_64 *s64, *plist64;
if(object->mh_filetype == MH_OBJECT) {
fatal_arch(arch, member, "Can't use the -l option on .o files "
"(filetypes of MH_OBJECT) for: ");
return;
}
text = NULL;
text64 = NULL;
plist = NULL;
plist64 = NULL;
if(object->mh != NULL){
start_offset = 0;
lc = object->load_commands;
for(i = 0; i < object->mh->ncmds && start_offset == 0; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(sg->filesize != 0 && sg->fileoff == 0){
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
if(sg->nsects > 0){
start_offset = s->offset;
for(j = 0; j < sg->nsects; j++){
if(strcmp(s->segname, SEG_TEXT) == 0 &&
strcmp(s->sectname, "__info_plist") == 0 &&
s->size != 0 && plist == NULL){
plist = s;
text = sg;
}
s++;
}
}
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(start_offset == 0)
start_offset = sizeof(struct mach_header) +
object->mh->sizeofcmds;
object->object_size -= (object->seg_linkedit->fileoff -
start_offset);
if(plist != NULL) {
object->output_new_content = object->object_addr +
object->seg_bitcode->fileoff;
object->output_new_content_size =
object->seg_bitcode->filesize + plist->size;
object->output_new_content =
allocate(object->output_new_content_size);
memcpy(object->output_new_content,
object->object_addr + plist->offset,
plist->size);
memcpy(object->output_new_content + plist->size,
object->object_addr + object->seg_bitcode->fileoff,
object->seg_bitcode->filesize);
plist->offset = start_offset;
text->fileoff = plist->offset;
text->filesize = plist->size;
start_offset += plist->size;
}
else {
object->output_new_content = object->object_addr +
object->seg_bitcode->fileoff;
object->output_new_content_size = object->seg_bitcode->filesize;
}
object->seg_bitcode->fileoff = start_offset;
sect_offset = object->seg_bitcode->fileoff;
s = (struct section *)((char *)object->seg_bitcode +
sizeof(struct segment_command));
for(i = 0; i < object->seg_bitcode->nsects; i++){
s->offset = sect_offset;
sect_offset += s->offset;
s++;
}
start_offset += object->seg_bitcode->filesize;
object->input_sym_info_size = object->seg_linkedit->filesize;
object->seg_linkedit->fileoff = start_offset;
}
else{
start_offset = 0;
lc = object->load_commands;
for(i = 0; i < object->mh64->ncmds && start_offset == 0; i++){
if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
if(sg64->filesize != 0 && sg64->fileoff == 0){
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
if(sg64->nsects > 0){
start_offset = s64->offset;
for(j = 0; j < sg64->nsects; j++){
if(strcmp(s64->segname, SEG_TEXT) == 0 &&
strcmp(s64->sectname, "__info_plist") == 0 &&
s64->size != 0 && plist64 == NULL){
plist64 = s64;
text64 = sg64;
}
s64++;
}
}
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(start_offset == 0)
start_offset = sizeof(struct mach_header_64) +
object->mh64->sizeofcmds;
object->object_size -= (object->seg_linkedit64->fileoff -
start_offset);
if(plist64 != NULL) {
object->output_new_content = object->object_addr +
object->seg_bitcode64->fileoff;
object->output_new_content_size =
object->seg_bitcode64->filesize + plist64->size;
object->output_new_content =
allocate(object->output_new_content_size);
memcpy(object->output_new_content,
object->object_addr + plist64->offset,
plist64->size);
memcpy(object->output_new_content + plist64->size,
object->object_addr + object->seg_bitcode64->fileoff,
object->seg_bitcode64->filesize);
plist64->offset = start_offset;
text64->fileoff = plist64->offset;
text64->filesize = plist64->size;
start_offset += plist64->size;
}
else {
object->output_new_content = object->object_addr +
object->seg_bitcode64->fileoff;
object->output_new_content_size =
object->seg_bitcode64->filesize;
}
object->seg_bitcode64->fileoff = start_offset;
sect_offset = object->seg_bitcode64->fileoff;
s64 = (struct section_64 *)((char *)object->seg_bitcode64 +
sizeof(struct segment_command_64));
for(i = 0; i < object->seg_bitcode64->nsects; i++){
s64->offset = sect_offset;
sect_offset += s64->offset;
s64++;
}
start_offset += object->seg_bitcode64->filesize;
object->input_sym_info_size = object->seg_linkedit64->filesize;
object->seg_linkedit64->fileoff = start_offset;
}
offset = start_offset;
if(object->dyld_info != NULL){
object->output_dyld_info = NULL;
object->output_dyld_info_size = 0;
object->dyld_info->rebase_off = 0;
object->dyld_info->rebase_size = 0;
object->dyld_info->bind_off = 0;
object->dyld_info->bind_size = 0;
object->dyld_info->weak_bind_off = 0;
object->dyld_info->weak_bind_size = 0;
object->dyld_info->lazy_bind_off = 0;
object->dyld_info->lazy_bind_size = 0;
object->dyld_info->export_off = 0;
object->dyld_info->export_size = 0;
}
if(object->dyst != NULL){
object->output_loc_relocs = NULL;
object->dyst->locreloff = 0;
object->dyst->nlocrel = 0;
}
if(object->split_info_cmd != NULL){
object->output_split_info_data = NULL;
object->output_split_info_data_size = 0;
object->split_info_cmd->dataoff = 0;
object->split_info_cmd->datasize = 0;
}
if(object->func_starts_info_cmd != NULL){
object->output_func_start_info_data = NULL;
object->output_func_start_info_data_size = 0;
object->func_starts_info_cmd->dataoff = 0;
object->func_starts_info_cmd->datasize = 0;
}
if(object->data_in_code_cmd != NULL){
object->output_data_in_code_info_data = NULL;
object->output_data_in_code_info_data_size = 0;
object->data_in_code_cmd->dataoff = 0;
object->data_in_code_cmd->datasize = 0;
}
if(object->code_sign_drs_cmd != NULL){
object->output_code_sign_drs_info_data = NULL;
object->output_code_sign_drs_info_data_size = 0;
object->code_sign_drs_cmd->dataoff = 0;
object->code_sign_drs_cmd->datasize = 0;
}
if(object->link_opt_hint_cmd != NULL){
object->output_link_opt_hint_info_data = NULL;
object->output_link_opt_hint_info_data_size = 0;
object->link_opt_hint_cmd->dataoff = 0;
object->link_opt_hint_cmd->datasize = 0;
}
if(object->st != NULL){
object->output_symbols = NULL;
object->output_symbols64 = NULL;
object->output_nsymbols = 0;
object->st->nsyms = 0;
object->st->symoff = 0;
}
if(object->hints_cmd != NULL){
object->output_hints = NULL;
object->hints_cmd->offset = 0;
object->hints_cmd->nhints = 0;
}
if(object->dyst != NULL){
object->output_ilocalsym = 0;
object->output_nlocalsym = 0;
object->output_iextdefsym = 0;
object->output_nextdefsym = 0;
object->output_iundefsym = 0;
object->output_nundefsym = 0;
object->dyst->ilocalsym = 0;
object->dyst->nlocalsym = 0;
object->dyst->iextdefsym = 0;
object->dyst->nextdefsym = 0;
object->dyst->iundefsym = 0;
object->dyst->nundefsym = 0;
object->output_ext_relocs = NULL;
object->dyst->nextrel = 0;
object->dyst->extreloff = 0;
object->output_indirect_symtab = NULL;
object->dyst->nindirectsyms = 0;
object->dyst->indirectsymoff = 0;
object->output_tocs = NULL;
object->output_ntoc = 0;
object->dyst->tocoff = 0;
object->output_mods = NULL;
object->output_mods64 = NULL;
object->output_nmodtab = 0;
object->dyst->modtaboff = 0;
object->output_refs = NULL;
object->output_nextrefsyms = 0;
object->dyst->extrefsymoff = 0;
}
if(object->st != NULL){
object->output_strings = fake_string_table;
object->output_strings_size = sizeof(fake_string_table);
object->st->stroff = offset;
object->st->strsize = sizeof(fake_string_table);
offset += sizeof(fake_string_table);
}
if(object->code_sig_cmd != NULL){
object->output_code_sig_data = NULL;
object->output_code_sig_data_size = 0;
}
object->output_sym_info_size = offset - start_offset;
if(object->mh != NULL)
object->seg_linkedit->filesize = object->output_sym_info_size;
else
object->seg_linkedit64->filesize = object->output_sym_info_size;
leave_only_bitcode_load_commands(arch, object,
plist != NULL || plist64 != NULL);
}
static
void
strip_bitcode_from_load_commands(
struct arch *arch,
struct object *object)
{
uint32_t i, mh_ncmds, new_ncmds, mh_sizeofcmds, new_sizeofcmds;
struct load_command *lc1, *lc2, *new_load_commands;
struct segment_command *sg;
struct segment_command_64 *sg64;
if(object->mh != NULL){
mh_ncmds = object->mh->ncmds;
mh_sizeofcmds = object->mh->sizeofcmds;
}
else{
mh_ncmds = object->mh64->ncmds;
mh_sizeofcmds = object->mh64->sizeofcmds;
}
new_load_commands = allocate(mh_sizeofcmds);
memset(new_load_commands, '\0', mh_sizeofcmds);
lc1 = object->load_commands;
lc2 = new_load_commands;
new_ncmds = 0;
new_sizeofcmds = 0;
for(i = 0; i < mh_ncmds; i++){
if(lc1->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc1;
if(strcmp(sg->segname, "__LLVM") != 0 || mflag){
memcpy(lc2, lc1, lc1->cmdsize);
new_ncmds++;
new_sizeofcmds += lc2->cmdsize;
lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
}
}
else if(lc1->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc1;
if(strcmp(sg64->segname, "__LLVM") != 0 || mflag){
memcpy(lc2, lc1, lc1->cmdsize);
new_ncmds++;
new_sizeofcmds += lc2->cmdsize;
lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
}
}
else if(lc1->cmd != LC_CODE_SIGNATURE &&
lc1->cmd != LC_DYLIB_CODE_SIGN_DRS){
memcpy(lc2, lc1, lc1->cmdsize);
new_ncmds++;
new_sizeofcmds += lc2->cmdsize;
lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
memcpy(object->load_commands, new_load_commands, new_sizeofcmds);
if(mh_sizeofcmds > new_sizeofcmds)
memset((char *)object->load_commands + new_sizeofcmds,
'\0', (mh_sizeofcmds - new_sizeofcmds));
if(object->mh != NULL) {
object->mh->sizeofcmds = new_sizeofcmds;
object->mh->ncmds = new_ncmds;
} else {
object->mh64->sizeofcmds = new_sizeofcmds;
object->mh64->ncmds = new_ncmds;
}
free(new_load_commands);
reset_pointers_for_object_load_commands(arch, object);
object->code_sig_cmd = NULL;
object->code_sign_drs_cmd = NULL;
}
static
void
leave_only_bitcode_load_commands(
struct arch *arch,
struct object *object,
enum bool keeping_plist)
{
uint32_t i, j, mh_ncmds, new_ncmds, mh_sizeofcmds, new_sizeofcmds;
struct load_command *lc1, *lc2, *new_load_commands;
struct segment_command *sg;
struct segment_command_64 *sg64;
struct section *s;
struct section_64 *s64;
struct entry_point_command *ep;
struct encryption_info_command *encrypt_info;
struct encryption_info_command_64 *encrypt_info64;
if(object->mh != NULL){
mh_ncmds = object->mh->ncmds;
mh_sizeofcmds = object->mh->sizeofcmds;
}
else{
mh_ncmds = object->mh64->ncmds;
mh_sizeofcmds = object->mh64->sizeofcmds;
}
new_load_commands = allocate(mh_sizeofcmds);
memset(new_load_commands, '\0', mh_sizeofcmds);
lc1 = object->load_commands;
lc2 = new_load_commands;
new_ncmds = 0;
new_sizeofcmds = 0;
for(i = 0; i < mh_ncmds; i++){
if(lc1->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc1;
if(strcmp(sg->segname, "__LLVM") != 0 &&
strcmp(sg->segname, SEG_LINKEDIT) != 0){
if(keeping_plist == FALSE ||
strcmp(sg->segname, SEG_TEXT) != 0){
sg->vmaddr = 0;
sg->vmsize = 0;
sg->fileoff = 0;
sg->filesize = 0;
}
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
if(keeping_plist == FALSE ||
strcmp(s->segname, SEG_TEXT) != 0 ||
strcmp(s->sectname, "__info_plist") != 0){
s->addr = 0;
s->size = 0;
s->offset = 0;
s->reloff = 0;
s->nreloc = 0;
s->reserved1 = 0;
}
s++;
}
}
memcpy(lc2, lc1, lc1->cmdsize);
new_ncmds++;
new_sizeofcmds += lc2->cmdsize;
lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
}
else if(lc1->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc1;
if(strcmp(sg64->segname, "__LLVM") != 0 &&
strcmp(sg64->segname, SEG_LINKEDIT) != 0){
if(keeping_plist == FALSE ||
strcmp(sg64->segname, SEG_TEXT) != 0){
sg64->vmaddr = 0;
sg64->vmsize = 0;
sg64->fileoff = 0;
sg64->filesize = 0;
}
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
for(j = 0; j < sg64->nsects; j++){
if(keeping_plist == FALSE ||
strcmp(s64->segname, SEG_TEXT) != 0 ||
strcmp(s64->sectname, "__info_plist") != 0){
s64->addr = 0;
s64->size = 0;
s64->offset = 0;
s64->reloff = 0;
s64->nreloc = 0;
s64->reserved1 = 0;
}
s64++;
}
}
memcpy(lc2, lc1, lc1->cmdsize);
new_ncmds++;
new_sizeofcmds += lc2->cmdsize;
lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
}
else if(lc1->cmd != LC_CODE_SIGNATURE &&
lc1->cmd != LC_DYLIB_CODE_SIGN_DRS){
if(lc1->cmd == LC_MAIN){
ep = (struct entry_point_command *)lc1;
ep->entryoff = 0;
}
else if(lc1->cmd == LC_ENCRYPTION_INFO){
encrypt_info = (struct encryption_info_command *)lc1;
encrypt_info->cryptoff = 0;
encrypt_info->cryptsize = 0;
}
else if(lc1->cmd == LC_ENCRYPTION_INFO_64){
encrypt_info64 = (struct encryption_info_command_64 *)lc1;
encrypt_info64->cryptoff = 0;
encrypt_info64->cryptsize = 0;
}
memcpy(lc2, lc1, lc1->cmdsize);
new_ncmds++;
new_sizeofcmds += lc2->cmdsize;
lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
memcpy(object->load_commands, new_load_commands, new_sizeofcmds);
if(mh_sizeofcmds > new_sizeofcmds)
memset((char *)object->load_commands + new_sizeofcmds,
'\0', (mh_sizeofcmds - new_sizeofcmds));
if(object->mh != NULL) {
object->mh->sizeofcmds = new_sizeofcmds;
object->mh->ncmds = new_ncmds;
} else {
object->mh64->sizeofcmds = new_sizeofcmds;
object->mh64->ncmds = new_ncmds;
}
free(new_load_commands);
reset_pointers_for_object_load_commands(arch, object);
object->code_sig_cmd = NULL;
object->code_sign_drs_cmd = NULL;
}
static
void
reset_pointers_for_object_load_commands(
struct arch *arch,
struct object *object)
{
uint32_t i, mh_ncmds;
struct load_command *lc;
struct segment_command *sg;
struct segment_command_64 *sg64;
if(object->mh != NULL)
mh_ncmds = object->mh->ncmds;
else
mh_ncmds = object->mh64->ncmds;
lc = object->load_commands;
for(i = 0; i < mh_ncmds; i++){
switch(lc->cmd){
case LC_SYMTAB:
object->st = (struct symtab_command *)lc;
break;
case LC_DYSYMTAB:
object->dyst = (struct dysymtab_command *)lc;
break;
case LC_TWOLEVEL_HINTS:
object->hints_cmd = (struct twolevel_hints_command *)lc;
break;
case LC_PREBIND_CKSUM:
object->cs = (struct prebind_cksum_command *)lc;
break;
case LC_SEGMENT:
sg = (struct segment_command *)lc;
if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
object->seg_linkedit = sg;
else if(strcmp(sg->segname, "__LLVM") == 0)
object->seg_bitcode = sg;
break;
case LC_SEGMENT_64:
sg64 = (struct segment_command_64 *)lc;
if(strcmp(sg64->segname, SEG_LINKEDIT) == 0)
object->seg_linkedit64 = sg64;
else if(strcmp(sg64->segname, "__LLVM") == 0)
object->seg_bitcode64 = sg64;
break;
case LC_SEGMENT_SPLIT_INFO:
object->split_info_cmd = (struct linkedit_data_command *)lc;
break;
case LC_FUNCTION_STARTS:
object->func_starts_info_cmd =
(struct linkedit_data_command *)lc;
break;
case LC_DATA_IN_CODE:
object->data_in_code_cmd =
(struct linkedit_data_command *)lc;
break;
case LC_LINKER_OPTIMIZATION_HINT:
object->link_opt_hint_cmd =
(struct linkedit_data_command *)lc;
break;
case LC_DYLD_INFO_ONLY:
case LC_DYLD_INFO:
object->dyld_info = (struct dyld_info_command *)lc;
case LC_DYLIB_CODE_SIGN_DRS:
object->code_sign_drs_cmd = (struct linkedit_data_command *)lc;
break;
case LC_CODE_SIGNATURE:
object->code_sig_cmd = (struct linkedit_data_command *)lc;
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
static
void
make_ld_process_mh_object(
struct arch *arch,
struct member *member,
struct object *object)
{
if(rflag)
some_slice_has_bitcode = TRUE;
make_ld_r_object(arch, object);
setup_symbolic_info_for_mh_object(arch, member, object);
}
static
void
make_ld_r_object(
struct arch *arch,
struct object *object)
{
enum byte_sex host_byte_sex;
char *input_file, *output_file;
int fd;
struct ofile *ld_r_ofile;
struct arch *ld_r_archs;
uint32_t ld_r_narchs, save_errors;
host_byte_sex = get_host_byte_sex();
if(object->object_byte_sex != host_byte_sex){
if(object->mh != NULL){
if(swap_object_headers(object->mh, object->load_commands) ==
FALSE)
fatal("internal error: swap_object_headers() failed");
}
else{
if(swap_object_headers(object->mh64, object->load_commands) ==
FALSE)
fatal("internal error: swap_object_headers() failed");
}
}
input_file = makestr("/tmp/bitcode_strip.XXXXXX", NULL);
input_file = mktemp(input_file);
if((fd = open(input_file, O_WRONLY|O_CREAT, 0600)) < 0)
system_fatal("can't open temporary file: %s", input_file);
if(write(fd, object->object_addr, object->object_size) !=
object->object_size)
system_fatal("can't write temporary file: %s", input_file);
if(close(fd) == -1)
system_fatal("can't close temporary file: %s", input_file);
output_file = makestr("/tmp/bitcode_strip.XXXXXX", NULL);
output_file = mktemp(output_file);
reset_execute_list();
add_execute_list_with_prefix("ld");
add_execute_list("-keep_private_externs");
add_execute_list("-r");
if(rflag){
add_execute_list("-bitcode_process_mode");
add_execute_list("strip");
}
else if(mflag){
add_execute_list("-bitcode_process_mode");
add_execute_list("marker");
}
add_execute_list(input_file);
add_execute_list("-o");
add_execute_list(output_file);
if(execute_list(vflag) == 0)
fatal("internal link edit command failed");
save_errors = errors;
errors = 0;
ld_r_ofile = breakout(output_file, &ld_r_archs, &ld_r_narchs, FALSE);
if(errors)
goto make_ld_r_object_cleanup;
checkout(ld_r_archs, ld_r_narchs);
if(ld_r_narchs != 1 ||
ld_r_archs->type != OFILE_Mach_O ||
ld_r_archs->object == NULL ||
ld_r_archs->object->mh_filetype != MH_OBJECT)
fatal("internal link edit command failed to produce a thin Mach-O "
"object file");
*object = *ld_r_archs->object;
object->ld_r_ofile = ld_r_ofile;
free_archs(ld_r_archs, ld_r_narchs);
make_ld_r_object_cleanup:
errors += save_errors;
if(unlink(input_file) == -1)
system_fatal("can't remove temporary file: %s", input_file);
if(unlink(output_file) == -1)
system_fatal("can't remove temporary file: %s", output_file);
free(input_file);
free(output_file);
}
static
void
setup_symbolic_info_for_mh_object(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t offset, start_offset;
offset = UINT_MAX;
if(object->seg_linkedit != NULL || object->seg_linkedit64 != NULL)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain a "
"link edit segment");
if(object->dyst != NULL && object->dyst->nlocrel != 0)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain "
"local relocation entries in the dynamic symbol table");
if(object->func_starts_info_cmd != NULL &&
object->func_starts_info_cmd->datasize != 0 &&
object->func_starts_info_cmd->dataoff < offset)
offset = object->func_starts_info_cmd->dataoff;
if(object->data_in_code_cmd != NULL &&
object->data_in_code_cmd->datasize != 0 &&
object->data_in_code_cmd->dataoff < offset)
offset = object->data_in_code_cmd->dataoff;
if(object->link_opt_hint_cmd != NULL &&
object->link_opt_hint_cmd->datasize != 0 &&
object->link_opt_hint_cmd->dataoff < offset)
offset = object->link_opt_hint_cmd->dataoff;
if(object->st->nsyms != 0 &&
object->st->symoff < offset)
offset = object->st->symoff;
if(object->dyst != NULL && object->dyst->nextrel != 0)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain "
"external relocation entries in the dynamic symbol "
"table");
if(object->dyst != NULL &&
object->dyst->nindirectsyms != 0 &&
object->dyst->indirectsymoff < offset)
offset = object->dyst->indirectsymoff;
if(object->dyst != NULL && object->dyst->ntoc)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain "
"toc entries in the dynamic symbol table");
if(object->dyst != NULL && object->dyst->nmodtab != 0)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain "
"module entries in the dynamic symbol table");
if(object->dyst != NULL && object->dyst->nextrefsyms != 0)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain "
"external reference entries in the dynamic symbol "
"table");
if(object->st->strsize != 0 &&
object->st->stroff < offset)
offset = object->st->stroff;
start_offset = offset;
object->input_sym_info_size = 0;
object->output_sym_info_size = 0;
if(object->dyld_info != NULL)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain a "
"dyld info");
if(object->split_info_cmd != NULL)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain a "
"split info load command");
if(object->func_starts_info_cmd != NULL){
object->input_sym_info_size +=
object->func_starts_info_cmd->datasize;
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;
object->func_starts_info_cmd->dataoff = offset;
offset += 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_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;
object->data_in_code_cmd->dataoff = offset;
offset += object->data_in_code_cmd->datasize;
}
if(object->code_sign_drs_cmd != NULL)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain a "
"code signature load command");
if(object->link_opt_hint_cmd != NULL){
object->input_sym_info_size +=
object->link_opt_hint_cmd->datasize;
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->link_opt_hint_cmd->dataoff = offset;
offset += object->link_opt_hint_cmd->datasize;
}
if(object->st != NULL && object->st->nsyms != 0){
if(object->mh != NULL){
object->input_sym_info_size +=
object->st->nsyms * sizeof(struct nlist);
object->output_symbols = (struct nlist *)
(object->object_addr + object->st->symoff);
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist(object->output_symbols,
object->st->nsyms,
get_host_byte_sex());
object->output_symbols64 = NULL;
}
else{
object->input_sym_info_size +=
object->st->nsyms * sizeof(struct nlist_64);
object->output_symbols64 = (struct nlist_64 *)
(object->object_addr + object->st->symoff);
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist_64(object->output_symbols64,
object->st->nsyms,
get_host_byte_sex());
object->output_symbols = NULL;
}
object->output_nsymbols = object->st->nsyms;
object->st->symoff = offset;
if(object->mh != NULL)
offset += object->st->nsyms * sizeof(struct nlist);
else
offset += object->st->nsyms * sizeof(struct nlist_64);
}
else if(object->st != NULL && object->st->nsyms == 0)
object->st->symoff = 0;
if(object->hints_cmd != NULL)
fatal_arch(arch, member, "malformed MH_OBJECT should not contain a "
"two level hints load command");
if(object->dyst != NULL){
object->output_ilocalsym = object->dyst->ilocalsym;
object->output_nlocalsym = object->dyst->nlocalsym;
object->output_iextdefsym = object->dyst->iextdefsym;
object->output_nextdefsym = object->dyst->nextdefsym;
object->output_iundefsym = object->dyst->iundefsym;
object->output_nundefsym = object->dyst->nundefsym;
if(object->dyst->nindirectsyms != 0){
object->input_sym_info_size +=
object->dyst->nindirectsyms * sizeof(uint32_t) +
object->input_indirectsym_pad;
object->output_indirect_symtab = (uint32_t *)
(object->object_addr + object->dyst->indirectsymoff);
object->dyst->indirectsymoff = offset;
offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
object->input_indirectsym_pad;
}
else
object->dyst->indirectsymoff = 0;
}
if(object->st != NULL && object->st->strsize != 0){
object->input_sym_info_size += object->st->strsize;
object->output_strings = object->object_addr + object->st->stroff;
object->output_strings_size = object->st->strsize;
object->st->stroff = offset;
offset += object->st->strsize;
}
else{
object->st->stroff = 0;
}
object->output_sym_info_size = offset - start_offset;
}