#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#include <libc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <mach-o/loader.h>
#include <mach-o/reloc.h>
#include <mach-o/nlist.h>
#include <mach-o/stab.h>
#include "stuff/breakout.h"
#include "stuff/allocate.h"
#include "stuff/errors.h"
#include "stuff/rnd.h"
#include "stuff/reloc.h"
#include "stuff/reloc.h"
#include "stuff/symbol_list.h"
#include "stuff/unix_standard_mode.h"
#include "stuff/execute.h"
#ifdef TRIE_SUPPORT
#include <mach-o/prune_trie.h>
#endif
__private_extern__
char *progname = NULL;
static char *output_file;
static char *sfile;
static char *Rfile;
static uint32_t Aflag;
static uint32_t iflag;
#ifdef NMEDIT
static uint32_t pflag;
#else
static char *dfile;
static uint32_t uflag;
static uint32_t rflag;
static uint32_t nflag;
static uint32_t Sflag;
static uint32_t xflag;
static uint32_t Xflag;
static uint32_t cflag;
static uint32_t no_uuid;
static uint32_t vflag;
static uint32_t lflag;
static uint32_t strip_all = 1;
static enum bool default_dyld_executable = FALSE;
#endif
static struct symbol_list *save_symbols = NULL;
static uint32_t nsave_symbols = 0;
static struct symbol_list *remove_symbols = NULL;
static uint32_t nremove_symbols = 0;
static int32_t *saves = NULL;
#ifndef NMEDIT
static int32_t *ref_saves = NULL;
#else
static enum bool *nmedits = NULL;
#endif
static struct nlist *symbols = NULL;
static struct nlist_64 *symbols64 = NULL;
static uint32_t nsyms = 0;
static char *strings = NULL;
static uint32_t strsize = 0;
static uint32_t *indirectsyms = NULL;
static uint32_t nindirectsyms = 0;
static struct nlist *new_symbols = NULL;
static struct nlist_64 *new_symbols64 = NULL;
static uint32_t new_nsyms = 0;
static char *new_strings = NULL;
static uint32_t new_strsize = 0;
static uint32_t new_nlocalsym = 0;
static uint32_t new_nextdefsym = 0;
static uint32_t new_nundefsym = 0;
#if defined(TRIE_SUPPORT) && !defined(NMEDIT)
static uint32_t inew_nextdefsym = 0;
#endif
static struct dylib_table_of_contents *new_tocs = NULL;
static uint32_t new_ntoc = 0;
static struct dylib_reference *new_refs = NULL;
static uint32_t new_nextrefsyms = 0;
#ifdef NMEDIT
static struct dylib_module *new_mods = NULL;
static struct dylib_module_64 *new_mods64 = NULL;
static uint32_t new_nmodtab = 0;
#endif
#ifndef NMEDIT
static char **debug_filenames = NULL;
static uint32_t ndebug_filenames = 0;
struct undef_map {
uint32_t index;
struct nlist symbol;
};
struct undef_map64 {
uint32_t index;
struct nlist_64 symbol64;
};
static char *qsort_strings = NULL;
#endif
static void usage(
void);
static void strip_file(
char *input_file,
struct arch_flag *arch_flags,
uint32_t narch_flags,
enum bool all_archs);
static void strip_arch(
struct arch *archs,
uint32_t narchs,
struct arch_flag *arch_flags,
uint32_t narch_flags,
enum bool all_archs);
static void strip_object(
struct arch *arch,
struct member *member,
struct object *object);
static uint32_t get_starting_syminfo_offset(
struct object *object);
static void check_object_relocs(
struct arch *arch,
struct member *member,
struct object *object,
char *segname,
char *sectname,
uint64_t sectsize,
char *contents,
struct relocation_info *relocs,
uint32_t nreloc,
struct nlist *symbols,
struct nlist_64 *symbols64,
uint32_t nsyms,
char *strings,
int32_t *missing_reloc_symbols,
enum byte_sex host_byte_sex);
static void check_indirect_symtab(
struct arch *arch,
struct member *member,
struct object *object,
uint32_t nitems,
uint32_t reserved1,
uint32_t section_type,
char *contents,
struct nlist *symbols,
struct nlist_64 *symbols64,
uint32_t nsyms,
char *strings,
int32_t *missing_reloc_symbols,
enum byte_sex host_byte_sex);
#ifndef NMEDIT
static enum bool strip_symtab(
struct arch *arch,
struct member *member,
struct object *object,
struct dylib_table_of_contents *tocs,
uint32_t ntoc,
struct dylib_module *mods,
struct dylib_module_64 *mods64,
uint32_t nmodtab,
struct dylib_reference *refs,
uint32_t nextrefsyms);
#ifdef TRIE_SUPPORT
static int prune(
const char *name);
#endif
static void make_ld_r_object(
struct arch *arch,
struct member *member,
struct object *object);
static void strip_LC_UUID_commands(
struct arch *arch,
struct member *member,
struct object *object);
#ifndef NMEDIT
static void strip_LC_CODE_SIGNATURE_commands(
struct arch *arch,
struct member *member,
struct object *object);
#endif
static enum bool private_extern_reference_by_module(
uint32_t symbol_index,
struct dylib_reference *refs,
uint32_t nextrefsyms);
static enum bool symbol_pointer_used(
uint32_t symbol_index,
uint32_t *indirectsyms,
uint32_t nindirectsyms);
static int cmp_qsort_undef_map(
const struct undef_map *sym1,
const struct undef_map *sym2);
static int cmp_qsort_undef_map_64(
const struct undef_map64 *sym1,
const struct undef_map64 *sym2);
#endif
#ifdef NMEDIT
static enum bool edit_symtab(
struct arch *arch,
struct member *member,
struct object *object,
struct nlist *symbols,
struct nlist_64 *symbols64,
uint32_t nsyms,
char *strings,
uint32_t strsize,
struct dylib_table_of_contents *tocs,
uint32_t ntoc,
struct dylib_module *mods,
struct dylib_module_64 *mods64,
uint32_t nmodtab,
struct dylib_reference *refs,
uint32_t nextrefsyms);
#endif
#ifndef NMEDIT
static void setup_debug_filenames(
char *dfile);
static int cmp_qsort_filename(
const char **name1,
const char **name2);
static int cmp_bsearch_filename(
const char *name1,
const char **name2);
#endif
#ifdef NMEDIT
static char *global_strings = NULL;
static int cmp_qsort_global(
const struct nlist **sym1,
const struct nlist **sym2);
static int cmp_qsort_global_64(
const struct nlist_64 **sym1,
const struct nlist_64 **sym2);
static int cmp_bsearch_global_stab(
const char *name,
const struct nlist **sym);
static int cmp_bsearch_global_stab_64(
const char *name,
const struct nlist_64 **sym);
static int cmp_bsearch_global(
const char *name,
const struct nlist **sym);
static int cmp_bsearch_global_64(
const char *name,
const struct nlist_64 **sym);
#endif
int
main(
int argc,
char *argv[],
char *envp[])
{
int i;
uint32_t j, args_left, files_specified;
struct arch_flag *arch_flags;
uint32_t narch_flags;
enum bool all_archs;
struct symbol_list *sp;
progname = argv[0];
arch_flags = NULL;
narch_flags = 0;
all_archs = FALSE;
files_specified = 0;
args_left = 1;
for (i = 1; i < argc; i++){
if(argv[i][0] == '-'){
if(argv[i][1] == '\0'){
args_left = 0;
break;
}
if(strcmp(argv[i], "-o") == 0){
if(i + 1 >= argc)
fatal("-o requires an argument");
if(output_file != NULL)
fatal("only one -o option allowed");
output_file = argv[i + 1];
i++;
}
else if(strcmp(argv[i], "-s") == 0){
if(i + 1 >= argc)
fatal("-s requires an argument");
if(sfile != NULL)
fatal("only one -s option allowed");
sfile = argv[i + 1];
i++;
}
else if(strcmp(argv[i], "-R") == 0){
if(i + 1 >= argc)
fatal("-R requires an argument");
if(Rfile != NULL)
fatal("only one -R option allowed");
Rfile = argv[i + 1];
i++;
}
#ifndef NMEDIT
else if(strcmp(argv[i], "-d") == 0){
if(i + 1 >= argc)
fatal("-d requires an argument");
if(dfile != NULL)
fatal("only one -d option allowed");
dfile = argv[i + 1];
i++;
}
else if(strcmp(argv[i], "-no_uuid") == 0){
no_uuid = 1;
}
#endif
else if(strcmp(argv[i], "-arch") == 0){
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++;
}
else{
for(j = 1; argv[i][j] != '\0'; j++){
switch(argv[i][j]){
#ifdef NMEDIT
case 'p':
pflag = 1;
break;
#else
case 'S':
Sflag = 1;
strip_all = 0;
break;
case 'X':
Xflag = 1;
strip_all = 0;
break;
case 'x':
xflag = 1;
strip_all = 0;
break;
case 'i':
iflag = 1;
break;
case 'u':
uflag = 1;
strip_all = 0;
break;
case 'r':
rflag = 1;
strip_all = 0;
break;
case 'n':
nflag = 1;
strip_all = 0;
break;
#endif
case 'A':
Aflag = 1;
#ifndef NMEDIT
strip_all = 0;
#endif
break;
#ifndef NMEDIT
case 'c':
cflag = 1;
strip_all = 0;
break;
case 'v':
vflag = 1;
break;
case 'l':
lflag = 1;
break;
#endif
default:
error("unrecognized option: %s", argv[i]);
usage();
}
}
}
}
else
files_specified++;
}
if(args_left == 0)
files_specified += argc - (i + 1);
if(files_specified > 1 && output_file != NULL){
error("-o <filename> can only be used when one file is specified");
usage();
}
if(sfile){
setup_symbol_list(sfile, &save_symbols, &nsave_symbols);
}
#ifdef NMEDIT
else{
if(Rfile == NULL && pflag == 0){
error("-s <filename>, -R <filename> or -p argument required");
usage();
}
}
#endif
if(Rfile){
setup_symbol_list(Rfile, &remove_symbols, &nremove_symbols);
if(sfile){
for(j = 0; j < nremove_symbols ; j++){
sp = bsearch(remove_symbols[j].name,
save_symbols, nsave_symbols,
sizeof(struct symbol_list),
(int (*)(const void *, const void *))
symbol_list_bsearch);
if(sp != NULL){
error("symbol name: %s is listed in both -s %s and -R "
"%s files (can't be both saved and removed)",
remove_symbols[j].name, sfile, Rfile);
}
}
if(errors)
exit(EXIT_FAILURE);
}
}
if(narch_flags == 0)
all_archs = TRUE;
#ifndef NMEDIT
if(dfile){
setup_debug_filenames(dfile);
}
#endif
files_specified = 0;
args_left = 1;
for (i = 1; i < argc; i++) {
if(args_left && argv[i][0] == '-'){
if(argv[i][1] == '\0')
args_left = 0;
else if(strcmp(argv[i], "-o") == 0 ||
strcmp(argv[i], "-s") == 0 ||
strcmp(argv[i], "-R") == 0 ||
#ifndef NMEDIT
strcmp(argv[i], "-d") == 0 ||
#endif
strcmp(argv[i], "-arch") == 0)
i++;
}
else{
char resolved_path[PATH_MAX + 1];
if(realpath(argv[i], resolved_path) == NULL)
strip_file(argv[i], arch_flags, narch_flags, all_archs);
else
strip_file(resolved_path, arch_flags,narch_flags,all_archs);
files_specified++;
}
}
if(files_specified == 0)
fatal("no files specified");
if(errors)
return(EXIT_FAILURE);
else
return(EXIT_SUCCESS);
}
static
void
usage(
void)
{
#ifndef NMEDIT
fprintf(stderr, "Usage: %s [-AnuSXx] [-] [-d filename] [-s filename] "
"[-R filename] [-o output] file [...] \n", progname);
#else
fprintf(stderr, "Usage: %s -s filename [-R filename] [-p] [-A] [-] "
"[-o output] file [...] \n",
progname);
#endif
exit(EXIT_FAILURE);
}
static
void
strip_file(
char *input_file,
struct arch_flag *arch_flags,
uint32_t narch_flags,
enum bool all_archs)
{
struct ofile *ofile;
struct arch *archs;
uint32_t narchs;
struct stat stat_buf;
uint32_t previous_errors;
enum bool unix_standard_mode;
int cwd_fd;
char *rename_file;
#ifndef NMEDIT
char *p;
#endif
archs = NULL;
narchs = 0;
previous_errors = errors;
errors = 0;
ofile = breakout(input_file, &archs, &narchs, FALSE);
if(errors)
return;
checkout(archs, narchs);
strip_arch(archs, narchs, arch_flags, narch_flags, all_archs);
if(errors){
free_archs(archs, narchs);
ofile_unmap(ofile);
return;
}
if(stat(input_file, &stat_buf) == -1)
system_error("can't stat input file: %s", input_file);
if(output_file != NULL){
writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
TRUE, FALSE, FALSE, NULL);
}
else{
unix_standard_mode = get_unix_standard_mode();
rename_file = NULL;
cwd_fd = -1;
#ifdef NMEDIT
output_file = makestr(input_file, ".nmedit", NULL);
#else
if(unix_standard_mode == TRUE &&
access(input_file, W_OK) == -1){
system_error("file: %s is not writable", input_file);
goto strip_file_return;
}
output_file = makestr(input_file, ".strip", NULL);
if(strlen(output_file) >= MAXPATHLEN){
if((p = rindex(output_file, '/')) != NULL){
if((cwd_fd = open(".", O_RDONLY, 0)) == -1){
system_error("can't open current working directory");
goto strip_file_return;
}
*p = '\0';
if(chdir(output_file) == -1){
system_error("can't change current working directory "
"to: %s", output_file);
goto strip_file_return;
}
p = rindex(input_file, '/');
rename_file = makestr(p + 1, NULL);
}
free(output_file);
output_file = makestr("strip.XXXXXX", NULL);
output_file = mktemp(output_file);
}
#endif
writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
TRUE, FALSE, FALSE, NULL);
if(rename_file != NULL){
if(rename(output_file, rename_file) == -1)
system_error("can't move temporary file: %s to file: %s",
output_file, rename_file);
free(rename_file);
}
else{
if(rename(output_file, input_file) == -1)
system_error("can't move temporary file: %s to input "
"file: %s", output_file, input_file);
}
free(output_file);
output_file = NULL;
if(cwd_fd != -1){
if(fchdir(cwd_fd) == -1)
system_error("can't change back to previous working "
"directory");
if(close(cwd_fd) == -1)
system_error("can't close previous working directory");
}
}
#ifndef NMEDIT
strip_file_return:
#endif
free_archs(archs, narchs);
ofile_unmap(ofile);
errors += previous_errors;
}
static
void
strip_arch(
struct arch *archs,
uint32_t narchs,
struct arch_flag *arch_flags,
uint32_t narch_flags,
enum bool all_archs)
{
uint32_t i, j, k, offset, size, missing_syms;
cpu_type_t cputype;
cpu_subtype_t cpusubtype;
struct arch_flag host_arch_flag;
enum bool arch_process, any_processing, *arch_flag_processed, family;
const struct arch_flag *family_arch_flag;
any_processing = FALSE;
arch_flag_processed = NULL;
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++){
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_arch != NULL){
cputype = archs[i].fat_arch->cputype;
cpusubtype = archs[i].fat_arch->cpusubtype;
}
arch_process = FALSE;
if(all_archs == TRUE){
arch_process = TRUE;
}
else if(narch_flags != 0){
family = FALSE;
if(narch_flags == 1){
family_arch_flag =
get_arch_family_from_cputype(arch_flags[0].cputype);
if(family_arch_flag != NULL)
family = (enum bool)
((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
(arch_flags[0].cpusubtype & ~CPU_SUBTYPE_MASK));
}
for(j = 0; j < narch_flags; j++){
if(arch_flags[j].cputype == cputype &&
((arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
(cpusubtype & ~CPU_SUBTYPE_MASK) ||
family == TRUE)){
arch_process = TRUE;
arch_flag_processed[j] = TRUE;
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(archs[i].type == OFILE_ARCHIVE){
for(j = 0; j < archs[i].nmembers; j++){
if(archs[i].members[j].type == OFILE_Mach_O){
strip_object(archs + i, archs[i].members + j,
archs[i].members[j].object);
}
}
missing_syms = 0;
if(iflag == 0){
for(k = 0; k < nsave_symbols; k++){
if(save_symbols[k].seen == FALSE){
if(missing_syms == 0){
error_arch(archs + i, NULL, "symbols names "
"listed in: %s not in: ", sfile);
missing_syms = 1;
}
fprintf(stderr, "%s\n", save_symbols[k].name);
}
}
}
for(k = 0; k < nsave_symbols; k++){
save_symbols[k].seen = FALSE;
}
missing_syms = 0;
if(iflag == 0){
for(k = 0; k < nremove_symbols; k++){
if(remove_symbols[k].seen == FALSE){
if(missing_syms == 0){
error_arch(archs + i, NULL, "symbols names "
"listed in: %s not defined in: ",
Rfile);
missing_syms = 1;
}
fprintf(stderr, "%s\n", remove_symbols[k].name);
}
}
}
for(k = 0; k < nremove_symbols; k++){
remove_symbols[k].seen = FALSE;
}
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, 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(archs[i].members[j].ar_hdr->ar_size, "%-*ld",
(int)sizeof(archs[i].members[j].ar_hdr->ar_size),
(long)(size));
memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG,
(int)sizeof(archs[i].members[j].ar_hdr->ar_fmag));
}
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){
strip_object(archs + i, NULL, archs[i].object);
}
else {
warning_arch(archs + i, NULL, "can't process non-object and "
"non-archive file: ");
return;
}
}
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);
}
static
void
strip_object(
struct arch *arch,
struct member *member,
struct object *object)
{
enum byte_sex host_byte_sex;
uint32_t offset;
struct dylib_table_of_contents *tocs;
uint32_t ntoc;
struct dylib_module *mods;
struct dylib_module_64 *mods64;
uint32_t nmodtab;
struct dylib_reference *refs;
uint32_t nextrefsyms;
uint32_t i, j;
struct load_command *lc;
struct segment_command *sg;
struct segment_command_64 *sg64;
struct section *s;
struct section_64 *s64;
struct relocation_info *relocs;
struct scattered_relocation_info *sreloc;
int32_t missing_reloc_symbols;
uint32_t stride, section_type, nitems;
char *contents;
uint32_t dyld_info_start;
uint32_t dyld_info_end;
#ifndef NMEDIT
uint32_t flags;
uint32_t k;
#endif
uint32_t ncmds;
host_byte_sex = get_host_byte_sex();
if(object->mh_filetype == MH_DYLIB_STUB){
if((object->mh != NULL && object->mh->ncmds == 0) ||
(object->mh64 != NULL && object->mh64->ncmds == 0)){
return;
}
}
if(object->mh_filetype == MH_DSYM)
fatal_arch(arch, member, "can't process dSYM companion file: ");
if(object->st == NULL || object->st->nsyms == 0){
warning_arch(arch, member, "input object file stripped: ");
return;
}
nsyms = object->st->nsyms;
if(object->mh != NULL){
symbols = (struct nlist *)
(object->object_addr + object->st->symoff);
if(object->object_byte_sex != host_byte_sex)
swap_nlist(symbols, nsyms, host_byte_sex);
symbols64 = NULL;
}
else{
symbols = NULL;
symbols64 = (struct nlist_64 *)
(object->object_addr + object->st->symoff);
if(object->object_byte_sex != host_byte_sex)
swap_nlist_64(symbols64, nsyms, host_byte_sex);
}
strings = object->object_addr + object->st->stroff;
strsize = object->st->strsize;
#ifndef NMEDIT
if(object->mh != NULL)
flags = object->mh->flags;
else
flags = object->mh64->flags;
if(object->mh_filetype == MH_DYLIB &&
(flags & MH_PREBOUND) != MH_PREBOUND){
arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
}
if(object->mh_filetype != MH_DYLIB && cflag)
fatal_arch(arch, member, "-c can't be used on non-dynamic "
"library: ");
#endif
if(object->mh_filetype == MH_DYLIB_STUB)
fatal_arch(arch, member, "dynamic stub library can't be changed "
"once created: ");
if(object->mh_filetype == MH_DYLIB){
tocs = (struct dylib_table_of_contents *)
(object->object_addr + object->dyst->tocoff);
ntoc = object->dyst->ntoc;
nmodtab = object->dyst->nmodtab;
if(object->mh != NULL){
mods = (struct dylib_module *)
(object->object_addr + object->dyst->modtaboff);
if(object->object_byte_sex != host_byte_sex)
swap_dylib_module(mods, nmodtab, host_byte_sex);
mods64 = NULL;
}
else{
mods = NULL;
mods64 = (struct dylib_module_64 *)
(object->object_addr + object->dyst->modtaboff);
if(object->object_byte_sex != host_byte_sex)
swap_dylib_module_64(mods64, nmodtab, host_byte_sex);
}
refs = (struct dylib_reference *)
(object->object_addr + object->dyst->extrefsymoff);
nextrefsyms = object->dyst->nextrefsyms;
if(object->object_byte_sex != host_byte_sex){
swap_dylib_table_of_contents(tocs, ntoc, host_byte_sex);
swap_dylib_reference(refs, nextrefsyms, host_byte_sex);
}
#ifndef NMEDIT
if(cflag){
arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
lc = object->load_commands;
if(object->mh != NULL){
ncmds = object->mh->ncmds;
object->mh_filetype = MH_DYLIB_STUB;
object->mh->filetype = MH_DYLIB_STUB;
}
else{
ncmds = object->mh64->ncmds;
object->mh_filetype = MH_DYLIB_STUB;
object->mh64->filetype = MH_DYLIB_STUB;
}
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(strcmp(sg->segname, SEG_LINKEDIT) != 0){
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
section_type = s[j].flags & SECTION_TYPE;
if(section_type != S_SYMBOL_STUBS &&
section_type != S_LAZY_SYMBOL_POINTERS &&
section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
section_type != S_NON_LAZY_SYMBOL_POINTERS){
s[j].size = 0;
}
s[j].addr = 0;
s[j].offset = 0;
s[j].reloff = 0;
}
sg->fileoff = 0;
sg->filesize = 0;
}
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
if(strcmp(sg64->segname, SEG_LINKEDIT) != 0){
s64 = (struct section_64 *)
((char *)sg64 +
sizeof(struct segment_command_64));
for(j = 0; j < sg64->nsects; j++){
section_type = s64[j].flags & SECTION_TYPE;
if(section_type != S_SYMBOL_STUBS &&
section_type != S_LAZY_SYMBOL_POINTERS &&
section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
section_type != S_NON_LAZY_SYMBOL_POINTERS){
s64[j].size = 0;
}
s64[j].addr = 0;
s64[j].offset = 0;
s64[j].reloff = 0;
}
sg64->fileoff = 0;
sg64->filesize = 0;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(object->mh != NULL){
object->object_size -= (object->seg_linkedit->fileoff -
(sizeof(struct mach_header) +
object->mh->sizeofcmds));
object->seg_linkedit->fileoff =
sizeof(struct mach_header) +
object->mh->sizeofcmds;
}
else{
object->object_size -= (object->seg_linkedit64->fileoff -
(sizeof(struct mach_header_64) +
object->mh64->sizeofcmds));
object->seg_linkedit64->fileoff =
sizeof(struct mach_header_64) +
object->mh64->sizeofcmds;
}
}
#endif
}
else{
tocs = NULL;
ntoc = 0;
mods = NULL;
mods64 = NULL;
nmodtab = 0;
refs = NULL;
nextrefsyms = 0;
}
if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
nindirectsyms = object->dyst->nindirectsyms;
indirectsyms = (uint32_t *)
(object->object_addr + object->dyst->indirectsymoff);
if(object->object_byte_sex != host_byte_sex)
swap_indirect_symbols(indirectsyms, nindirectsyms,
host_byte_sex);
}
else{
indirectsyms = NULL;
nindirectsyms = 0;
}
if(object->mh != NULL)
object->input_sym_info_size =
nsyms * sizeof(struct nlist) +
strsize;
else
object->input_sym_info_size =
nsyms * sizeof(struct nlist_64) +
strsize;
#ifndef NMEDIT
if(object->mh != NULL)
flags = object->mh->flags;
else
flags = object->mh64->flags;
if(strip_all &&
(flags & MH_DYLDLINK) == MH_DYLDLINK &&
object->mh_filetype == MH_EXECUTE)
default_dyld_executable = TRUE;
else
default_dyld_executable = FALSE;
#endif
#ifndef NMEDIT
if(sfile != NULL || Rfile != NULL || dfile != NULL || Aflag || uflag ||
Sflag || xflag || Xflag || nflag || rflag ||
default_dyld_executable || object->mh_filetype == MH_DYLIB ||
object->mh_filetype == MH_DYLINKER)
#endif
{
#ifdef NMEDIT
if(edit_symtab(arch, member, object, symbols, symbols64, nsyms,
strings, strsize, tocs, ntoc, mods, mods64, nmodtab, refs,
nextrefsyms) == FALSE)
return;
#else
if(strip_symtab(arch, member, object, tocs, ntoc, mods, mods64,
nmodtab, refs, nextrefsyms) == FALSE)
return;
if(no_uuid == TRUE)
strip_LC_UUID_commands(arch, member, object);
#endif
if(object->mh != NULL)
object->output_sym_info_size =
new_nsyms * sizeof(struct nlist) +
new_strsize;
else
object->output_sym_info_size =
new_nsyms * sizeof(struct nlist_64) +
new_strsize;
object->st->nsyms = new_nsyms;
object->st->strsize = new_strsize;
if(object->mh != NULL)
object->output_symbols = new_symbols;
else
object->output_symbols64 = new_symbols64;
object->output_nsymbols = new_nsyms;
object->output_strings = new_strings;
object->output_strings_size = new_strsize;
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;
object->output_sym_info_size += object->output_dyld_info_size;
if(nsave_symbols != 0){
warning_arch(arch, NULL, "removing global symbols from a "
"final linked no longer supported. Use "
"-exported_symbols_list at link time when "
"building: ");
}
}
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->code_sig_cmd != NULL){
#ifndef NMEDIT
if(!cflag)
#endif
{
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->dyst != NULL){
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;
if(object->dyst->nindirectsyms != 0){
object->output_indirect_symtab = indirectsyms;
if(object->object_byte_sex != host_byte_sex)
swap_indirect_symbols(indirectsyms, nindirectsyms,
object->object_byte_sex);
}
if(object->mh_filetype == MH_DYLIB ||
object->mh_filetype == MH_DYLIB_STUB){
object->output_tocs = new_tocs;
object->output_ntoc = new_ntoc;
#ifdef NMEDIT
if(object->mh != NULL)
object->output_mods = new_mods;
else
object->output_mods64 = new_mods64;
object->output_nmodtab = new_nmodtab;
#else
object->output_mods = mods;
object->output_nmodtab = nmodtab;
#endif
object->output_refs = new_refs;
object->output_nextrefsyms = new_nextrefsyms;
if(object->object_byte_sex != host_byte_sex){
swap_dylib_table_of_contents(new_tocs, new_ntoc,
object->object_byte_sex);
#ifdef NMEDIT
if(object->mh != NULL)
swap_dylib_module(new_mods, new_nmodtab,
object->object_byte_sex);
else
swap_dylib_module_64(new_mods64, new_nmodtab,
object->object_byte_sex);
#else
if(object->mh != NULL)
swap_dylib_module(mods, nmodtab,
object->object_byte_sex);
else
swap_dylib_module_64(mods64, nmodtab,
object->object_byte_sex);
#endif
swap_dylib_reference(new_refs, new_nextrefsyms,
object->object_byte_sex);
}
}
if(object->dyld_info != NULL){
object->input_sym_info_size += object->dyld_info->rebase_size
+ object->dyld_info->bind_size
+ object->dyld_info->weak_bind_size
+ object->dyld_info->lazy_bind_size
+ object->dyld_info->export_size;
}
object->input_sym_info_size +=
object->dyst->nlocrel * sizeof(struct relocation_info) +
object->dyst->nextrel * sizeof(struct relocation_info) +
object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
object->dyst->nextrefsyms * sizeof(struct dylib_reference);
if(object->mh != NULL){
object->input_sym_info_size +=
object->dyst->nmodtab * sizeof(struct dylib_module) +
object->dyst->nindirectsyms * sizeof(uint32_t);
}
else{
object->input_sym_info_size +=
object->dyst->nmodtab * sizeof(struct dylib_module_64) +
object->dyst->nindirectsyms * sizeof(uint32_t) +
object->input_indirectsym_pad;
}
#ifndef NMEDIT
if(!cflag)
#endif
{
object->output_sym_info_size +=
object->dyst->nlocrel * sizeof(struct relocation_info) +
object->dyst->nextrel * sizeof(struct relocation_info);
}
object->output_sym_info_size +=
new_ntoc * sizeof(struct dylib_table_of_contents)+
new_nextrefsyms * sizeof(struct dylib_reference) +
object->dyst->nindirectsyms * sizeof(uint32_t) +
object->input_indirectsym_pad;
if(object->mh != NULL){
object->output_sym_info_size +=
object->dyst->nmodtab * sizeof(struct dylib_module);
}
else{
object->output_sym_info_size +=
object->dyst->nmodtab * sizeof(struct dylib_module_64);
}
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->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->code_sig_cmd != NULL){
object->input_sym_info_size =
rnd(object->input_sym_info_size, 16);
object->input_sym_info_size +=
object->code_sig_cmd->datasize;
#ifndef NMEDIT
if(cflag){
strip_LC_CODE_SIGNATURE_commands(arch, member, object);
}
else
#endif
{
object->output_sym_info_size =
rnd(object->output_sym_info_size, 16);
object->output_sym_info_size +=
object->code_sig_cmd->datasize;
}
}
object->dyst->ntoc = new_ntoc;
object->dyst->nextrefsyms = new_nextrefsyms;
offset = get_starting_syminfo_offset(object);
if(object->dyld_info != 0){
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->nlocrel != 0){
object->output_loc_relocs = (struct relocation_info *)
(object->object_addr + object->dyst->locreloff);
#ifndef NMEDIT
if(cflag){
object->dyst->nlocrel = 0;
object->dyst->locreloff = 0;
}
else
#endif
{
object->dyst->locreloff = offset;
offset += object->dyst->nlocrel *
sizeof(struct relocation_info);
}
}
else
object->dyst->locreloff = 0;
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->st->nsyms != 0){
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
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->nextrel != 0){
object->output_ext_relocs = (struct relocation_info *)
(object->object_addr + object->dyst->extreloff);
#ifndef NMEDIT
if(cflag){
object->dyst->nextrel = 0;
object->dyst->extreloff = 0;
}
else
#endif
{
object->dyst->extreloff = offset;
offset += object->dyst->nextrel *
sizeof(struct relocation_info);
}
}
else
object->dyst->extreloff = 0;
if(object->dyst->nindirectsyms != 0){
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->dyst->tocoff = offset;
offset += object->dyst->ntoc *
sizeof(struct dylib_table_of_contents);
}
else
object->dyst->tocoff = 0;
if(object->dyst->nmodtab != 0){
#ifndef NMEDIT
if(cflag){
if(object->mh != NULL){
for(k = 0; k < object->dyst->nmodtab; k++){
mods[k].iinit_iterm = 0;
mods[k].ninit_nterm = 0;
mods[k].iextrel = 0;
mods[k].nextrel = 0;
mods[k].objc_module_info_addr = 0;
mods[k].objc_module_info_size = 0;
}
}
else{
for(k = 0; k < object->dyst->nmodtab; k++){
mods64[k].iinit_iterm = 0;
mods64[k].ninit_nterm = 0;
mods64[k].iextrel = 0;
mods64[k].nextrel = 0;
mods64[k].objc_module_info_addr = 0;
mods64[k].objc_module_info_size = 0;
}
}
}
#endif
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->dyst->extrefsymoff = offset;
offset += object->dyst->nextrefsyms *
sizeof(struct dylib_reference);
}
else
object->dyst->extrefsymoff = 0;
if(object->st->strsize != 0){
object->st->stroff = offset;
offset += object->st->strsize;
}
else
object->st->stroff = 0;
if(object->code_sig_cmd != NULL){
offset = rnd(offset, 16);
object->code_sig_cmd->dataoff = offset;
offset += object->code_sig_cmd->datasize;
}
}
else{
if(new_strsize != 0){
if(object->mh != NULL)
object->st->stroff = object->st->symoff +
new_nsyms * sizeof(struct nlist);
else
object->st->stroff = object->st->symoff +
new_nsyms * sizeof(struct nlist_64);
}
else
object->st->stroff = 0;
if(new_nsyms == 0)
object->st->symoff = 0;
}
}
#ifndef NMEDIT
else{
if(saves != NULL)
free(saves);
saves = (int32_t *)allocate(object->st->nsyms * sizeof(int32_t));
bzero(saves, object->st->nsyms * sizeof(int32_t));
if(object->dyst != NULL){
object->input_sym_info_size +=
object->dyst->nlocrel * sizeof(struct relocation_info) +
object->dyst->nextrel * sizeof(struct relocation_info) +
object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
object->dyst->nextrefsyms * sizeof(struct dylib_reference);
if(object->mh != NULL){
object->input_sym_info_size +=
object->dyst->nmodtab * sizeof(struct dylib_module) +
object->dyst->nindirectsyms * sizeof(uint32_t);
}
else{
object->input_sym_info_size +=
object->dyst->nmodtab * sizeof(struct dylib_module_64) +
object->dyst->nindirectsyms * sizeof(uint32_t) +
object->input_indirectsym_pad;
}
}
offset = get_starting_syminfo_offset(object);
object->st->symoff = 0;
object->st->nsyms = 0;
object->st->stroff = 0;
object->st->strsize = 0;
if(object->dyst != NULL){
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_sym_info_size = 0;
if(object->dyst != NULL){
if(object->dyst->nextrel != 0){
object->output_ext_relocs = (struct relocation_info *)
(object->object_addr + object->dyst->extreloff);
}
if(object->dyst->nlocrel != 0){
object->output_loc_relocs = (struct relocation_info *)
(object->object_addr + object->dyst->locreloff);
object->output_sym_info_size +=
object->dyst->nlocrel * sizeof(struct relocation_info);
object->dyst->locreloff = offset;
offset += object->dyst->nlocrel *
sizeof(struct relocation_info);
}
if(object->dyst->nindirectsyms != 0){
object->output_indirect_symtab = (uint32_t *)
(object->object_addr +
object->dyst->indirectsymoff);
if(object->object_byte_sex != host_byte_sex)
swap_indirect_symbols(
object->output_indirect_symtab,
object->dyst->nindirectsyms,
object->object_byte_sex);
object->output_sym_info_size +=
object->dyst->nindirectsyms * sizeof(uint32_t) +
object->input_indirectsym_pad;
object->dyst->indirectsymoff = offset;
offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
object->input_indirectsym_pad;
}
}
}
#endif
if(object->cs != NULL)
object->cs->cksum = 0;
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;
}
else if(object->seg_linkedit64 != NULL){
object->seg_linkedit64->filesize -= object->input_sym_info_size;
object->seg_linkedit64->filesize += object->output_sym_info_size;
object->seg_linkedit64->vmsize = object->seg_linkedit64->filesize;
}
missing_reloc_symbols = 0;
lc = object->load_commands;
if(object->mh != NULL)
ncmds = object->mh->ncmds;
else
ncmds = object->mh64->ncmds;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT &&
object->seg_linkedit != (struct segment_command *)lc){
sg = (struct segment_command *)lc;
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
if(s->nreloc != 0){
if(s->reloff + s->nreloc *
sizeof(struct relocation_info) >
object->object_size){
fatal_arch(arch, member, "truncated or malformed "
"object (relocation entries for section (%.16s,"
"%.16s) extends past the end of the file)",
s->segname, s->sectname);
}
relocs = (struct relocation_info *)
(object->object_addr + s->reloff);
if(object->object_byte_sex != host_byte_sex)
swap_relocation_info(relocs, s->nreloc,
host_byte_sex);
if(s->offset + s->size > object->object_size){
fatal_arch(arch, member, "truncated or malformed "
"object (contents of section (%.16s,"
"%.16s) extends past the end of the file)",
s->segname, s->sectname);
}
contents = object->object_addr + s->offset;
check_object_relocs(arch, member, object, s->segname,
s->sectname, s->size, contents, relocs, s->nreloc,
symbols, symbols64, nsyms, strings,
&missing_reloc_symbols, host_byte_sex);
if(object->object_byte_sex != host_byte_sex)
swap_relocation_info(relocs, s->nreloc,
object->object_byte_sex);
}
s++;
}
}
else if(lc->cmd == LC_SEGMENT_64 &&
object->seg_linkedit64 != (struct segment_command_64 *)lc){
sg64 = (struct segment_command_64 *)lc;
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
for(j = 0; j < sg64->nsects; j++){
if(s64->nreloc != 0){
if(s64->reloff + s64->nreloc *
sizeof(struct relocation_info) >
object->object_size){
fatal_arch(arch, member, "truncated or malformed "
"object (relocation entries for section (%.16s,"
"%.16s) extends past the end of the file)",
s64->segname, s64->sectname);
}
relocs = (struct relocation_info *)
(object->object_addr + s64->reloff);
if(object->object_byte_sex != host_byte_sex)
swap_relocation_info(relocs, s64->nreloc,
host_byte_sex);
if(s64->offset + s64->size > object->object_size){
fatal_arch(arch, member, "truncated or malformed "
"object (contents of section (%.16s,"
"%.16s) extends past the end of the file)",
s64->segname, s64->sectname);
}
contents = object->object_addr + s64->offset;
check_object_relocs(arch, member, object, s64->segname,
s64->sectname, s64->size, contents, relocs,
s64->nreloc, symbols, symbols64, nsyms, strings,
&missing_reloc_symbols, host_byte_sex);
if(object->object_byte_sex != host_byte_sex)
swap_relocation_info(relocs, s64->nreloc,
object->object_byte_sex);
}
s64++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(object->dyst != NULL && object->dyst->nextrel != 0){
relocs = object->output_ext_relocs;
if(object->object_byte_sex != host_byte_sex)
swap_relocation_info(relocs, object->dyst->nextrel,
host_byte_sex);
for(i = 0; i < object->dyst->nextrel; i++){
if((relocs[i].r_address & R_SCATTERED) == 0 &&
relocs[i].r_extern == 1){
if(relocs[i].r_symbolnum > nsyms){
fatal_arch(arch, member, "bad r_symbolnum for external "
"relocation entry %d in: ", i);
}
if(saves[relocs[i].r_symbolnum] == 0){
if(missing_reloc_symbols == 0){
error_arch(arch, member, "symbols referenced by "
"relocation entries that can't be stripped in: ");
missing_reloc_symbols = 1;
}
if(object->mh != NULL){
fprintf(stderr, "%s\n", strings + symbols
[relocs[i].r_symbolnum].n_un.n_strx);
}
else {
fprintf(stderr, "%s\n", strings + symbols64
[relocs[i].r_symbolnum].n_un.n_strx);
}
saves[relocs[i].r_symbolnum] = -1;
}
if(saves[relocs[i].r_symbolnum] != -1){
relocs[i].r_symbolnum =
saves[relocs[i].r_symbolnum] - 1;
}
}
else{
fatal_arch(arch, member, "bad external relocation entry "
"%d (not external) in: ", i);
}
if((relocs[i].r_address & R_SCATTERED) == 0){
if(reloc_has_pair(object->mh_cputype, relocs[i].r_type))
i++;
}
else{
sreloc = (struct scattered_relocation_info *)relocs + i;
if(reloc_has_pair(object->mh_cputype, sreloc->r_type))
i++;
}
}
if(object->object_byte_sex != host_byte_sex)
swap_relocation_info(relocs, object->dyst->nextrel,
object->object_byte_sex);
}
if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
if(object->object_byte_sex != host_byte_sex)
swap_indirect_symbols(object->output_indirect_symtab,
object->dyst->nindirectsyms, host_byte_sex);
lc = object->load_commands;
if(object->mh != NULL)
ncmds = object->mh->ncmds;
else
ncmds = object->mh64->ncmds;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT &&
object->seg_linkedit != (struct segment_command *)lc){
sg = (struct segment_command *)lc;
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
section_type = s->flags & SECTION_TYPE;
if(section_type == S_LAZY_SYMBOL_POINTERS ||
section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
section_type == S_NON_LAZY_SYMBOL_POINTERS)
stride = 4;
else if(section_type == S_SYMBOL_STUBS)
stride = s->reserved2;
else{
s++;
continue;
}
nitems = s->size / stride;
contents = object->object_addr + s->offset;
check_indirect_symtab(arch, member, object, nitems,
s->reserved1, section_type, contents, symbols,
symbols64, nsyms, strings, &missing_reloc_symbols,
host_byte_sex);
s++;
}
}
else if(lc->cmd == LC_SEGMENT_64 &&
object->seg_linkedit64 != (struct segment_command_64 *)lc){
sg64 = (struct segment_command_64 *)lc;
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
for(j = 0; j < sg64->nsects; j++){
section_type = s64->flags & SECTION_TYPE;
if(section_type == S_LAZY_SYMBOL_POINTERS ||
section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
section_type == S_NON_LAZY_SYMBOL_POINTERS)
stride = 8;
else if(section_type == S_SYMBOL_STUBS)
stride = s64->reserved2;
else{
s64++;
continue;
}
nitems = s64->size / stride;
contents = object->object_addr + s64->offset;
check_indirect_symtab(arch, member, object, nitems,
s64->reserved1, section_type, contents, symbols,
symbols64, nsyms, strings, &missing_reloc_symbols,
host_byte_sex);
s64++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(object->object_byte_sex != host_byte_sex)
swap_indirect_symbols(object->output_indirect_symtab,
object->dyst->nindirectsyms, object->object_byte_sex);
}
if(object->code_sig_cmd != NULL)
warning_arch(arch, member, "changes being made to the file will "
"invalidate the code signature in: ");
}
static
uint32_t
get_starting_syminfo_offset(
struct object *object)
{
uint32_t offset;
if(object->seg_linkedit != NULL ||
object->seg_linkedit64 != NULL){
if(object->mh != NULL)
offset = object->seg_linkedit->fileoff;
else
offset = object->seg_linkedit64->fileoff;
}
else{
offset = UINT_MAX;
if(object->dyst != NULL &&
object->dyst->nlocrel != 0 &&
object->dyst->locreloff < offset)
offset = object->dyst->locreloff;
if(object->st->nsyms != 0 &&
object->st->symoff < offset)
offset = object->st->symoff;
if(object->dyst != NULL &&
object->dyst->nextrel != 0 &&
object->dyst->extreloff < offset)
offset = object->dyst->extreloff;
if(object->dyst != NULL &&
object->dyst->nindirectsyms != 0 &&
object->dyst->indirectsymoff < offset)
offset = object->dyst->indirectsymoff;
if(object->dyst != NULL &&
object->dyst->ntoc != 0 &&
object->dyst->tocoff < offset)
offset = object->dyst->tocoff;
if(object->dyst != NULL &&
object->dyst->nmodtab != 0 &&
object->dyst->modtaboff < offset)
offset = object->dyst->modtaboff;
if(object->dyst != NULL &&
object->dyst->nextrefsyms != 0 &&
object->dyst->extrefsymoff < offset)
offset = object->dyst->extrefsymoff;
if(object->st->strsize != 0 &&
object->st->stroff < offset)
offset = object->st->stroff;
}
return(offset);
}
static
void
check_object_relocs(
struct arch *arch,
struct member *member,
struct object *object,
char *segname,
char *sectname,
uint64_t sectsize,
char *contents,
struct relocation_info *relocs,
uint32_t nreloc,
struct nlist *symbols,
struct nlist_64 *symbols64,
uint32_t nsyms,
char *strings,
int32_t *missing_reloc_symbols,
enum byte_sex host_byte_sex)
{
uint32_t k, n_strx;
uint64_t n_value;
#ifdef NMEDIT
uint32_t value, n_ext;
uint64_t value64;
#endif
struct scattered_relocation_info *sreloc;
for(k = 0; k < nreloc; k++){
if((relocs[k].r_address & R_SCATTERED) == 0 &&
relocs[k].r_extern == 1){
if(relocs[k].r_symbolnum > nsyms){
fatal_arch(arch, member, "bad r_symbolnum for relocation "
"entry %d in section (%.16s,%.16s) in: ", k, segname,
sectname);
}
if(object->mh != NULL){
n_strx = symbols[relocs[k].r_symbolnum].n_un.n_strx;
n_value = symbols[relocs[k].r_symbolnum].n_value;
}
else{
n_strx = symbols64[relocs[k].r_symbolnum].n_un.n_strx;
n_value = symbols64[relocs[k].r_symbolnum].n_value;
}
#ifndef NMEDIT
if(saves[relocs[k].r_symbolnum] == 0){
if(*missing_reloc_symbols == 0){
error_arch(arch, member, "symbols referenced by "
"relocation entries that can't be stripped in: ");
*missing_reloc_symbols = 1;
}
fprintf(stderr, "%s\n", strings + n_strx);
saves[relocs[k].r_symbolnum] = -1;
}
#else
if(object->mh != NULL)
n_ext = new_symbols[saves[relocs[k].r_symbolnum] - 1].
n_type & N_EXT;
else
n_ext = new_symbols64[saves[relocs[k].r_symbolnum] - 1].
n_type & N_EXT;
if(n_ext != N_EXT &&
object->mh_cputype != CPU_TYPE_X86_64){
if(relocs[k].r_address + sizeof(int32_t) > sectsize){
fatal_arch(arch, member, "truncated or malformed "
"object (r_address of relocation entry %u of "
"section (%.16s,%.16s) extends past the end "
"of the section)", k, segname, sectname);
}
if(object->mh != NULL){
value = *(uint32_t *)
(contents + relocs[k].r_address);
if(object->object_byte_sex != host_byte_sex)
value = SWAP_INT(value);
if(relocs[k].r_type != 0 ||
relocs[k].r_length != 2){
fatal_arch(arch, member, "don't have "
"code to convert external relocation "
"entry %d in section (%.16s,%.16s) "
"for global coalesced symbol: %s "
"in: ", k, segname, sectname,
strings + n_strx);
}
value += n_value;
if(object->object_byte_sex != host_byte_sex)
value = SWAP_INT(value);
*(uint32_t *)(contents + relocs[k].r_address) =
value;
}
else{
value64 = *(uint64_t *)(contents + relocs[k].r_address);
if(object->object_byte_sex != host_byte_sex)
value64 = SWAP_LONG_LONG(value64);
if(relocs[k].r_type != 0 ||
relocs[k].r_length != 3){
fatal_arch(arch, member, "don't have "
"code to convert external relocation "
"entry %d in section (%.16s,%.16s) "
"for global coalesced symbol: %s "
"in: ", k, segname, sectname,
strings + n_strx);
}
value64 += n_value;
if(object->object_byte_sex != host_byte_sex)
value64 = SWAP_LONG_LONG(value64);
*(uint64_t *)(contents + relocs[k].r_address) = value64;
}
if(object->mh != NULL)
relocs[k].r_symbolnum =
new_symbols[saves[relocs[k].r_symbolnum] - 1].n_sect;
else
relocs[k].r_symbolnum =
new_symbols64[saves[relocs[k].r_symbolnum] - 1].n_sect;
relocs[k].r_extern = 0;
}
#endif
if(relocs[k].r_extern == 1 &&
saves[relocs[k].r_symbolnum] != -1){
relocs[k].r_symbolnum = saves[relocs[k].r_symbolnum] - 1;
}
}
if((relocs[k].r_address & R_SCATTERED) == 0){
if(reloc_has_pair(object->mh_cputype, relocs[k].r_type) == TRUE)
k++;
}
else{
sreloc = (struct scattered_relocation_info *)relocs + k;
if(reloc_has_pair(object->mh_cputype, sreloc->r_type) == TRUE)
k++;
}
}
}
static
void
check_indirect_symtab(
struct arch *arch,
struct member *member,
struct object *object,
uint32_t nitems,
uint32_t reserved1,
uint32_t section_type,
char *contents,
struct nlist *symbols,
struct nlist_64 *symbols64,
uint32_t nsyms,
char *strings,
int32_t *missing_reloc_symbols,
enum byte_sex host_byte_sex)
{
uint32_t k, index;
uint8_t n_type;
uint32_t n_strx, value;
uint64_t value64;
enum bool made_local;
for(k = 0; k < nitems; k++){
made_local = FALSE;
index = object->output_indirect_symtab[reserved1 + k];
if(index == INDIRECT_SYMBOL_LOCAL ||
index == INDIRECT_SYMBOL_ABS ||
index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS))
continue;
if(index > nsyms)
fatal_arch(arch, member,"indirect symbol table entry %d (past " "the end of the symbol table) in: ", reserved1 + k);
#ifdef NMEDIT
if(pflag == 0 && nmedits[index] == TRUE && saves[index] != -1)
#else
if(saves[index] == 0)
#endif
{
if(object->mh != NULL){
n_type = symbols[index].n_type;
n_strx = symbols[index].n_un.n_strx;
}
else{
n_type = symbols64[index].n_type;
n_strx = symbols64[index].n_un.n_strx;
}
if((n_type && N_TYPE) != N_UNDF &&
(n_type && N_TYPE) != N_PBUD &&
section_type == S_NON_LAZY_SYMBOL_POINTERS){
object->output_indirect_symtab[reserved1 + k] =
INDIRECT_SYMBOL_LOCAL;
if((n_type & N_TYPE) == N_ABS)
object->output_indirect_symtab[reserved1 + k] |=
INDIRECT_SYMBOL_ABS;
made_local = TRUE;
if(object->mh_filetype != MH_DYLIB_STUB){
if(object->mh != NULL){
value = symbols[index].n_value;
if (symbols[index].n_desc & N_ARM_THUMB_DEF)
value |= 1;
if(object->object_byte_sex != host_byte_sex)
value = SWAP_INT(value);
*(uint32_t *)(contents + k * 4) = value;
}
else{
value64 = symbols64[index].n_value;
if(object->object_byte_sex != host_byte_sex)
value64 = SWAP_LONG_LONG(value64);
*(uint64_t *)(contents + k * 8) = value64;
}
}
}
#ifdef NMEDIT
else {
object->output_indirect_symtab[reserved1 + k] =
saves[index] - 1;
}
#else
else{
if(*missing_reloc_symbols == 0){
error_arch(arch, member, "symbols referenced by "
"indirect symbol table entries that can't be "
"stripped in: ");
*missing_reloc_symbols = 1;
}
fprintf(stderr, "%s\n", strings + n_strx);
saves[index] = -1;
}
#endif
}
#ifdef NMEDIT
else
#else
if(made_local == FALSE && saves[index] != -1)
#endif
{
object->output_indirect_symtab[reserved1+k] = saves[index] - 1;
}
}
}
#ifndef NMEDIT
static
void
setup_debug_filenames(
char *dfile)
{
int fd, i, strings_size;
struct stat stat_buf;
char *strings, *p;
if((fd = open(dfile, O_RDONLY)) < 0){
system_error("can't open: %s", dfile);
return;
}
if(fstat(fd, &stat_buf) == -1){
system_error("can't stat: %s", dfile);
close(fd);
return;
}
strings_size = stat_buf.st_size;
strings = (char *)allocate(strings_size + 1);
strings[strings_size] = '\0';
if(read(fd, strings, strings_size) != strings_size){
system_error("can't read: %s", dfile);
close(fd);
return;
}
p = strings;
for(i = 0; i < strings_size; i++){
if(*p == '\n'){
*p = '\0';
ndebug_filenames++;
}
p++;
}
debug_filenames = (char **)allocate(ndebug_filenames * sizeof(char *));
p = strings;
for(i = 0; i < ndebug_filenames; i++){
debug_filenames[i] = p;
p += strlen(p) + 1;
}
qsort(debug_filenames, ndebug_filenames, sizeof(char *),
(int (*)(const void *, const void *))cmp_qsort_filename);
#ifdef DEBUG
printf("Debug filenames:\n");
for(i = 0; i < ndebug_filenames; i++){
printf("filename = %s\n", debug_filenames[i]);
}
#endif
}
static
enum bool
strip_symtab(
struct arch *arch,
struct member *member,
struct object *object,
struct dylib_table_of_contents *tocs,
uint32_t ntoc,
struct dylib_module *mods,
struct dylib_module_64 *mods64,
uint32_t nmodtab,
struct dylib_reference *refs,
uint32_t nextrefsyms)
{
uint32_t i, j, k, n, inew_syms, save_debug, missing_syms;
uint32_t missing_symbols;
char *p, *q, **pp, *basename;
struct symbol_list *sp;
uint32_t new_ext_strsize, len, *changes, inew_undefsyms;
unsigned char nsects;
struct load_command *lc;
struct segment_command *sg;
struct segment_command_64 *sg64;
struct section *s, **sections;
struct section_64 *s64, **sections64;
uint32_t ncmds, mh_flags, s_flags, n_strx;
struct nlist *sym;
struct undef_map *undef_map;
struct undef_map64 *undef_map64;
uint8_t n_type, n_sect;
uint16_t n_desc;
uint64_t n_value;
uint32_t module_name, iextdefsym, nextdefsym, ilocalsym, nlocalsym;
uint32_t irefsym, nrefsym;
enum bool has_dwarf, hack_5614542;
save_debug = 0;
if(saves != NULL)
free(saves);
changes = NULL;
for(i = 0; i < nsave_symbols; i++)
save_symbols[i].sym = NULL;
for(i = 0; i < nremove_symbols; i++)
remove_symbols[i].sym = NULL;
if(member == NULL){
for(i = 0; i < nsave_symbols; i++)
save_symbols[i].seen = FALSE;
for(i = 0; i < nremove_symbols; i++)
remove_symbols[i].seen = FALSE;
}
new_nsyms = 0;
if(object->mh != NULL)
new_strsize = sizeof(int32_t);
else
new_strsize = sizeof(int64_t);
new_nlocalsym = 0;
new_nextdefsym = 0;
new_nundefsym = 0;
new_ext_strsize = 0;
if(object->mh_filetype == MH_OBJECT && (Sflag || xflag)){
has_dwarf = FALSE;
lc = object->load_commands;
if(object->mh != NULL)
ncmds = object->mh->ncmds;
else
ncmds = object->mh64->ncmds;
for(i = 0; i < ncmds && has_dwarf == FALSE; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
if(s->flags & S_ATTR_DEBUG){
has_dwarf = TRUE;
break;
}
s++;
}
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
for(j = 0; j < sg64->nsects; j++){
if(s64->flags & S_ATTR_DEBUG){
has_dwarf = TRUE;
break;
}
s64++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if((lflag == TRUE && has_dwarf == TRUE) || object->mh64 != NULL)
make_ld_r_object(arch, member, object);
}
if(object->mh_filetype == MH_OBJECT &&
(object->mh64 != NULL && object->ld_r_ofile == NULL))
make_ld_r_object(arch, member, object);
saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
bzero(saves, nsyms * sizeof(int32_t));
nsects = 0;
lc = object->load_commands;
if(object->mh != NULL)
ncmds = object->mh->ncmds;
else
ncmds = object->mh64->ncmds;
for(i = 0; i < ncmds; i++){
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){
sections = allocate(nsects * sizeof(struct section *));
sections64 = NULL;
}
else{
sections = NULL;
sections64 = allocate(nsects * sizeof(struct section_64 *));
}
nsects = 0;
lc = object->load_commands;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++)
sections[nsects++] = s++;
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
for(j = 0; j < sg64->nsects; j++)
sections64[nsects++] = s64++;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
for(i = 0; i < nsyms; i++){
s_flags = 0;
if(object->mh != NULL){
mh_flags = object->mh->flags;
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
n_sect = symbols[i].n_sect;
if((n_type & N_TYPE) == N_SECT){
if(n_sect == 0 || n_sect > nsects){
error_arch(arch, member, "bad n_sect for symbol "
"table entry %d in: ", i);
return(FALSE);
}
s_flags = sections[n_sect - 1]->flags;
}
n_desc = symbols[i].n_desc;
n_value = symbols[i].n_value;
}
else{
mh_flags = object->mh64->flags;
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
n_sect = symbols64[i].n_sect;
if((n_type & N_TYPE) == N_SECT){
if(n_sect == 0 || n_sect > nsects){
error_arch(arch, member, "bad n_sect for symbol "
"table entry %d in: ", i);
return(FALSE);
}
s_flags = sections64[n_sect - 1]->flags;
}
n_desc = symbols64[i].n_desc;
n_value = symbols64[i].n_value;
}
if(n_strx != 0){
if(n_strx > strsize){
error_arch(arch, member, "bad string index for symbol "
"table entry %d in: ", i);
return(FALSE);
}
}
if((n_type & N_TYPE) == N_INDR){
if(n_value != 0){
if(n_value > strsize){
error_arch(arch, member, "bad string index for "
"indirect symbol table entry %d in: ", i);
return(FALSE);
}
}
}
if((n_type & N_EXT) == 0){
if(object->mh == NULL &&
object->mh64->cputype == CPU_TYPE_X86_64 &&
object->mh64->filetype == MH_OBJECT){
if(n_strx != 0)
new_strsize += strlen(strings + n_strx) + 1;
new_nlocalsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
else if((!strip_all && (Xflag || Sflag)) || dfile){
if(n_type & N_STAB){
if(dfile && n_type == N_SO){
if(n_strx != 0){
basename = strrchr(strings + n_strx, '/');
if(basename != NULL)
basename++;
else
basename = strings + n_strx;
pp = bsearch(basename, debug_filenames,
ndebug_filenames, sizeof(char *),
(int (*)(const void *, const void *)
)cmp_bsearch_filename);
if(*basename != '\0'){
if(pp != NULL)
save_debug = 1;
else
save_debug = 0;
}
else{
if(save_debug){
if(n_strx != 0)
new_strsize += strlen(strings +
n_strx) + 1;
new_nlocalsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
save_debug = 0;
}
}
else{
save_debug = 0;
}
}
if(saves[i] == 0 && (!Sflag || save_debug)){
if(n_strx != 0)
new_strsize += strlen(strings + n_strx) + 1;
new_nlocalsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
}
else{
if(xflag == 0 && (Sflag || Xflag)){
if(Xflag == 0 ||
(n_strx != 0 &&
strings[n_strx] != 'L')){
if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK ||
(n_type & N_TYPE) != N_SECT ||
(s_flags & S_ATTR_STRIP_STATIC_SYMS) !=
S_ATTR_STRIP_STATIC_SYMS){
new_strsize += strlen(strings + n_strx) + 1;
new_nlocalsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
}
}
if((n_type & N_PEXT) == N_PEXT){
if(saves[i] == 0 &&
private_extern_reference_by_module(
i, refs ,nextrefsyms) == TRUE){
if(n_strx != 0)
new_strsize += strlen(strings + n_strx) + 1;
new_nlocalsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
if(saves[i] == 0 &&
symbol_pointer_used(i, indirectsyms,
nindirectsyms) == TRUE){
if(n_strx != 0){
len = strlen(strings + n_strx) + 1;
new_strsize += len;
}
new_nlocalsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
}
}
}
else if((n_type & N_PEXT) == N_PEXT){
if(saves[i] == 0 && sfile){
sp = bsearch(strings + n_strx,
save_symbols, nsave_symbols,
sizeof(struct symbol_list),
(int (*)(const void *, const void *))
symbol_list_bsearch);
if(sp != NULL){
if(sp->sym == NULL){
if(object->mh != NULL)
sp->sym = &(symbols[i]);
else
sp->sym = &(symbols64[i]);
sp->seen = TRUE;
}
if(n_strx != 0)
new_strsize += strlen(strings + n_strx) + 1;
new_nlocalsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
}
if(saves[i] == 0 &&
private_extern_reference_by_module(
i, refs ,nextrefsyms) == TRUE){
if(n_strx != 0)
new_strsize += strlen(strings + n_strx) + 1;
new_nlocalsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
if(saves[i] == 0 &&
symbol_pointer_used(i, indirectsyms, nindirectsyms) ==
TRUE){
if(n_strx != 0){
len = strlen(strings + n_strx) + 1;
new_strsize += len;
}
new_nlocalsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
}
}
else{
if(Rfile &&
(object->mh != NULL ||
object->mh64->cputype != CPU_TYPE_X86_64 ||
object->mh64->filetype != MH_OBJECT)){
sp = bsearch(strings + n_strx,
remove_symbols, nremove_symbols,
sizeof(struct symbol_list),
(int (*)(const void *, const void *))
symbol_list_bsearch);
if(sp != NULL){
if((n_type & N_TYPE) == N_UNDF ||
(n_type & N_TYPE) == N_PBUD){
error_arch(arch, member, "symbol: %s undefined"
" and can't be stripped from: ",
sp->name);
}
else if(sp->sym != NULL){
sym = (struct nlist *)sp->sym;
if((sym->n_type & N_PEXT) != N_PEXT)
error_arch(arch, member, "more than one symbol "
"for: %s found in: ", sp->name);
}
else{
if(object->mh != NULL)
sp->sym = &(symbols[i]);
else
sp->sym = &(symbols64[i]);
sp->seen = TRUE;
}
if(n_desc & REFERENCED_DYNAMICALLY){
error_arch(arch, member, "symbol: %s is dynamically"
" referenced and can't be stripped "
"from: ", sp->name);
}
if((n_type & N_TYPE) == N_SECT &&
(s_flags & SECTION_TYPE) == S_COALESCED){
error_arch(arch, member, "symbol: %s is a global "
"coalesced symbol and can't be "
"stripped from: ", sp->name);
}
continue;
}
}
if(Aflag && (n_type & N_TYPE) == N_ABS &&
(n_value != 0 ||
(n_strx != 0 &&
strncmp(strings + n_strx,
".objc_class_name_",
sizeof(".objc_class_name_") - 1) == 0))){
len = strlen(strings + n_strx) + 1;
new_strsize += len;
new_ext_strsize += len;
new_nextdefsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
if(saves[i] == 0 && (uflag || default_dyld_executable) &&
((((n_type & N_TYPE) == N_UNDF) &&
n_value == 0) ||
(n_type & N_TYPE) == N_PBUD)){
if(n_strx != 0){
len = strlen(strings + n_strx) + 1;
new_strsize += len;
new_ext_strsize += len;
}
new_nundefsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
if(saves[i] == 0 && nflag &&
(n_type & N_TYPE) == N_SECT){
if(n_strx != 0){
len = strlen(strings + n_strx) + 1;
new_strsize += len;
new_ext_strsize += len;
}
new_nextdefsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
if(saves[i] == 0 && sfile){
sp = bsearch(strings + n_strx,
save_symbols, nsave_symbols,
sizeof(struct symbol_list),
(int (*)(const void *, const void *))
symbol_list_bsearch);
if(sp != NULL){
if(sp->sym != NULL){
sym = (struct nlist *)sp->sym;
if((sym->n_type & N_PEXT) != N_PEXT)
error_arch(arch, member, "more than one symbol "
"for: %s found in: ", sp->name);
}
else{
if(object->mh != NULL)
sp->sym = &(symbols[i]);
else
sp->sym = &(symbols64[i]);
sp->seen = TRUE;
len = strlen(strings + n_strx) + 1;
new_strsize += len;
new_ext_strsize += len;
if((n_type & N_TYPE) == N_UNDF ||
(n_type & N_TYPE) == N_PBUD)
new_nundefsym++;
else
new_nextdefsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
}
}
if(object->mh != NULL &&
saves[i] == 0 &&
(n_type & N_TYPE) == N_SECT &&
(s_flags & SECTION_TYPE) == S_COALESCED &&
symbol_pointer_used(i, indirectsyms, nindirectsyms) == TRUE){
if(n_strx != 0){
len = strlen(strings + n_strx) + 1;
new_strsize += len;
new_ext_strsize += len;
}
new_nextdefsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
if(saves[i] == 0 &&
(n_type & N_TYPE) == N_SECT &&
(n_desc & N_WEAK_DEF) != 0){
if(n_strx != 0){
len = strlen(strings + n_strx) + 1;
new_strsize += len;
new_ext_strsize += len;
}
new_nextdefsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
if(saves[i] == 0 && ((Xflag || Sflag || xflag) ||
((rflag || default_dyld_executable) &&
n_desc & REFERENCED_DYNAMICALLY))){
len = strlen(strings + n_strx) + 1;
new_strsize += len;
new_ext_strsize += len;
if((n_type & N_TYPE) == N_INDR){
len = strlen(strings + n_value) + 1;
new_strsize += len;
new_ext_strsize += len;
}
if((n_type & N_TYPE) == N_UNDF ||
(n_type & N_TYPE) == N_PBUD)
new_nundefsym++;
else
new_nextdefsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
if(saves[i] == 0 &&
object->mh == NULL &&
object->mh64->cputype == CPU_TYPE_X86_64 &&
object->mh64->filetype == MH_OBJECT){
len = strlen(strings + n_strx) + 1;
new_strsize += len;
new_ext_strsize += len;
if((n_type & N_TYPE) == N_INDR){
len = strlen(strings + n_value) + 1;
new_strsize += len;
new_ext_strsize += len;
}
if((n_type & N_TYPE) == N_UNDF ||
(n_type & N_TYPE) == N_PBUD)
new_nundefsym++;
else
new_nextdefsym++;
new_nsyms++;
saves[i] = new_nsyms;
}
}
}
for(i = 0; i < nmodtab; i++){
if(object->mh != NULL)
module_name = mods[i].module_name;
else
module_name = mods64[i].module_name;
if(module_name == 0 || module_name > strsize){
error_arch(arch, member, "bad string index for module_name "
"of module table entry %d in: ", i);
return(FALSE);
}
len = strlen(strings + module_name) + 1;
new_strsize += len;
new_ext_strsize += len;
}
missing_symbols = 0;
if(ref_saves != NULL)
free(ref_saves);
ref_saves = (int32_t *)allocate(nextrefsyms * sizeof(int32_t));
bzero(ref_saves, nextrefsyms * sizeof(int32_t));
changes = (uint32_t *)allocate(nsyms * sizeof(int32_t));
bzero(changes, nsyms * sizeof(int32_t));
new_nextrefsyms = 0;
for(i = 0; i < nextrefsyms; i++){
if(refs[i].isym > nsyms){
error_arch(arch, member, "bad symbol table index for "
"reference table entry %d in: ", i);
return(FALSE);
}
if(saves[refs[i].isym]){
new_nextrefsyms++;
ref_saves[i] = new_nextrefsyms;
}
else{
if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
if(changes[refs[i].isym] == 0){
if(object->mh != NULL)
n_strx = symbols[refs[i].isym].n_un.n_strx;
else
n_strx = symbols64[refs[i].isym].n_un.n_strx;
len = strlen(strings + n_strx) + 1;
new_strsize += len;
new_ext_strsize += len;
new_nundefsym++;
new_nsyms++;
changes[refs[i].isym] = new_nsyms;
new_nextrefsyms++;
ref_saves[i] = new_nextrefsyms;
}
}
else{
if(refs[i].flags ==
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
if(missing_symbols == 0){
error_arch(arch, member, "private extern symbols "
"referenced by modules can't be stripped in: ");
missing_symbols = 1;
}
if(object->mh != NULL)
n_strx = symbols[refs[i].isym].n_un.n_strx;
else
n_strx = symbols64[refs[i].isym].n_un.n_strx;
fprintf(stderr, "%s\n", strings + n_strx);
saves[refs[i].isym] = -1;
}
}
}
}
if(missing_symbols == 1)
return(FALSE);
if(member == NULL){
missing_syms = 0;
if(iflag == 0){
for(i = 0; i < nsave_symbols; i++){
if(save_symbols[i].sym == NULL){
if(missing_syms == 0){
error_arch(arch, member, "symbols names listed "
"in: %s not in: ", sfile);
missing_syms = 1;
}
fprintf(stderr, "%s\n", save_symbols[i].name);
}
}
}
missing_syms = 0;
if(iflag == 0 &&
(object->mh != NULL ||
object->mh64->cputype != CPU_TYPE_X86_64 ||
object->mh64->filetype != MH_OBJECT)){
for(i = 0; i < nremove_symbols; i++){
if(remove_symbols[i].sym == NULL){
if(missing_syms == 0){
error_arch(arch, member, "symbols names listed "
"in: %s not in: ", Rfile);
missing_syms = 1;
}
fprintf(stderr, "%s\n", remove_symbols[i].name);
}
}
}
}
if(new_nlocalsym == 0 && nindirectsyms != 0){
len = strlen("radr://5614542") + 1;
new_strsize += len;
new_nlocalsym++;
new_nsyms++;
hack_5614542 = TRUE;
}
else{
hack_5614542 = FALSE;
}
if(object->mh != NULL){
new_symbols = (struct nlist *)
allocate(new_nsyms * sizeof(struct nlist));
new_symbols64 = NULL;
}
else{
new_symbols = NULL;
new_symbols64 = (struct nlist_64 *)
allocate(new_nsyms * sizeof(struct nlist_64));
}
if(object->mh != NULL)
new_strsize = rnd(new_strsize, sizeof(int32_t));
else
new_strsize = rnd(new_strsize, sizeof(int64_t));
new_strings = (char *)allocate(new_strsize);
if(object->mh != NULL){
new_strings[new_strsize - 3] = '\0';
new_strings[new_strsize - 2] = '\0';
new_strings[new_strsize - 1] = '\0';
}
else{
new_strings[new_strsize - 7] = '\0';
new_strings[new_strsize - 6] = '\0';
new_strings[new_strsize - 5] = '\0';
new_strings[new_strsize - 4] = '\0';
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;
if(object->mh != NULL && new_strsize == sizeof(int32_t))
new_strsize = 0;
inew_syms = 0;
if(hack_5614542 == TRUE){
if(object->mh != NULL){
new_symbols[inew_syms].n_type = N_OPT;
new_symbols[inew_syms].n_sect = NO_SECT;
new_symbols[inew_syms].n_desc = 0;
new_symbols[inew_syms].n_value = 0x05614542;
}
else{
new_symbols64[inew_syms].n_type = N_OPT;
new_symbols64[inew_syms].n_sect = NO_SECT;
new_symbols64[inew_syms].n_desc = 0;
new_symbols64[inew_syms].n_value = 0x05614542;
}
strcpy(q, "radr://5614542");
if(object->mh != NULL)
new_symbols[inew_syms].n_un.n_strx =
q - new_strings;
else
new_symbols64[inew_syms].n_un.n_strx =
q - new_strings;
q += strlen(q) + 1;
inew_syms++;
}
for(i = 0; i < nsyms; i++){
if(saves[i]){
if(object->mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
}
if((n_type & N_EXT) == 0){
if(object->mh != NULL)
new_symbols[inew_syms] = symbols[i];
else
new_symbols64[inew_syms] = symbols64[i];
if(n_strx != 0){
strcpy(q, strings + n_strx);
if(object->mh != NULL)
new_symbols[inew_syms].n_un.n_strx =
q - new_strings;
else
new_symbols64[inew_syms].n_un.n_strx =
q - new_strings;
q += strlen(q) + 1;
}
inew_syms++;
saves[i] = inew_syms;
}
}
}
#ifdef TRIE_SUPPORT
inew_nextdefsym = inew_syms;
#endif
for(i = 0; i < nsyms; i++){
if(saves[i]){
if(object->mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
n_value = symbols[i].n_value;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
n_value = symbols64[i].n_value;
}
if((n_type & N_EXT) == N_EXT &&
((n_type & N_TYPE) != N_UNDF &&
(n_type & N_TYPE) != N_PBUD)){
if(object->mh != NULL)
new_symbols[inew_syms] = symbols[i];
else
new_symbols64[inew_syms] = symbols64[i];
if(n_strx != 0){
strcpy(p, strings + n_strx);
if(object->mh != NULL)
new_symbols[inew_syms].n_un.n_strx =
p - new_strings;
else
new_symbols64[inew_syms].n_un.n_strx =
p - new_strings;
p += strlen(p) + 1;
}
if((n_type & N_TYPE) == N_INDR){
if(n_value != 0){
strcpy(p, strings + n_value);
if(object->mh != NULL)
new_symbols[inew_syms].n_value =
p - new_strings;
else
new_symbols64[inew_syms].n_value =
p - new_strings;
p += strlen(p) + 1;
}
}
inew_syms++;
saves[i] = inew_syms;
}
}
}
inew_undefsyms = 0;
if(object->mh != NULL){
undef_map = (struct undef_map *)allocate(new_nundefsym *
sizeof(struct undef_map));
undef_map64 = NULL;
}
else{
undef_map = NULL;
undef_map64 = (struct undef_map64 *)allocate(new_nundefsym *
sizeof(struct undef_map64));
}
for(i = 0; i < nsyms; i++){
if(saves[i]){
if(object->mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
}
if((n_type & N_EXT) == N_EXT &&
((n_type & N_TYPE) == N_UNDF ||
(n_type & N_TYPE) == N_PBUD)){
if(object->mh != NULL)
undef_map[inew_undefsyms].symbol = symbols[i];
else
undef_map64[inew_undefsyms].symbol64 = symbols64[i];
if(n_strx != 0){
strcpy(p, strings + n_strx);
if(object->mh != NULL)
undef_map[inew_undefsyms].symbol.n_un.n_strx =
p - new_strings;
else
undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
p - new_strings;
p += strlen(p) + 1;
}
if(object->mh != NULL)
undef_map[inew_undefsyms].index = i;
else
undef_map64[inew_undefsyms].index = i;
inew_undefsyms++;
}
}
}
for(i = 0; i < nsyms; i++){
if(changes[i]){
if(object->mh != NULL)
n_strx = symbols[i].n_un.n_strx;
else
n_strx = symbols64[i].n_un.n_strx;
if(n_strx != 0){
strcpy(p, strings + n_strx);
if(object->mh != NULL)
undef_map[inew_undefsyms].symbol.n_un.n_strx =
p - new_strings;
else
undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
p - new_strings;
p += strlen(p) + 1;
}
if(object->mh != NULL){
undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT;
undef_map[inew_undefsyms].symbol.n_sect = NO_SECT;
undef_map[inew_undefsyms].symbol.n_desc = 0;
undef_map[inew_undefsyms].symbol.n_value = 0;
undef_map[inew_undefsyms].index = i;
}
else{
undef_map64[inew_undefsyms].symbol64.n_type = N_UNDF |N_EXT;
undef_map64[inew_undefsyms].symbol64.n_sect = NO_SECT;
undef_map64[inew_undefsyms].symbol64.n_desc = 0;
undef_map64[inew_undefsyms].symbol64.n_value = 0;
undef_map64[inew_undefsyms].index = i;
}
inew_undefsyms++;
}
}
qsort_strings = new_strings;
if(object->mh != NULL)
qsort(undef_map, new_nundefsym, sizeof(struct undef_map),
(int (*)(const void *, const void *))cmp_qsort_undef_map);
else
qsort(undef_map64, new_nundefsym, sizeof(struct undef_map64),
(int (*)(const void *, const void *))cmp_qsort_undef_map_64);
for(i = 0; i < new_nundefsym; i++){
if(object->mh != NULL){
new_symbols[inew_syms] = undef_map[i].symbol;
inew_syms++;
saves[undef_map[i].index] = inew_syms;
}
else{
new_symbols64[inew_syms] = undef_map64[i].symbol64;
inew_syms++;
saves[undef_map64[i].index] = inew_syms;
}
}
for(i = 0; i < nmodtab; i++){
if(object->mh != NULL){
strcpy(p, strings + mods[i].module_name);
mods[i].module_name = p - new_strings;
iextdefsym = mods[i].iextdefsym;
nextdefsym = mods[i].nextdefsym;
ilocalsym = mods[i].ilocalsym;
nlocalsym = mods[i].nlocalsym;
irefsym = mods[i].irefsym;
nrefsym = mods[i].nrefsym;
}
else{
strcpy(p, strings + mods64[i].module_name);
mods64[i].module_name = p - new_strings;
iextdefsym = mods64[i].iextdefsym;
nextdefsym = mods64[i].nextdefsym;
ilocalsym = mods64[i].ilocalsym;
nlocalsym = mods64[i].nlocalsym;
irefsym = mods64[i].irefsym;
nrefsym = mods64[i].nrefsym;
}
p += strlen(p) + 1;
if(iextdefsym > nsyms){
error_arch(arch, member, "bad index into externally defined "
"symbols of module table entry %d in: ", i);
return(FALSE);
}
if(iextdefsym + nextdefsym > nsyms){
error_arch(arch, member, "bad number of externally defined "
"symbols of module table entry %d in: ", i);
return(FALSE);
}
for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
if(saves[j] != 0 && changes[j] == 0)
break;
}
n = 0;
for(k = j; k < iextdefsym + nextdefsym; k++){
if(saves[k] != 0 && changes[k] == 0)
n++;
}
if(n == 0){
if(object->mh != NULL){
mods[i].iextdefsym = 0;
mods[i].nextdefsym = 0;
}
else{
mods64[i].iextdefsym = 0;
mods64[i].nextdefsym = 0;
}
}
else{
if(object->mh != NULL){
mods[i].iextdefsym = saves[j] - 1;
mods[i].nextdefsym = n;
}
else{
mods64[i].iextdefsym = saves[j] - 1;
mods64[i].nextdefsym = n;
}
}
if(ilocalsym > nsyms){
error_arch(arch, member, "bad index into symbols for local "
"symbols of module table entry %d in: ", i);
return(FALSE);
}
if(ilocalsym + nlocalsym > nsyms){
error_arch(arch, member, "bad number of local "
"symbols of module table entry %d in: ", i);
return(FALSE);
}
for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
if(saves[j] != 0)
break;
}
n = 0;
for(k = j; k < ilocalsym + nlocalsym; k++){
if(saves[k] != 0)
n++;
}
if(n == 0){
if(object->mh != NULL){
mods[i].ilocalsym = 0;
mods[i].nlocalsym = 0;
}
else{
mods64[i].ilocalsym = 0;
mods64[i].nlocalsym = 0;
}
}
else{
if(object->mh != NULL){
mods[i].ilocalsym = saves[j] - 1;
mods[i].nlocalsym = n;
}
else{
mods64[i].ilocalsym = saves[j] - 1;
mods64[i].nlocalsym = n;
}
}
if(irefsym > nextrefsyms){
error_arch(arch, member, "bad index into reference table "
"of module table entry %d in: ", i);
return(FALSE);
}
if(irefsym + nrefsym > nextrefsyms){
error_arch(arch, member, "bad number of reference table "
"entries of module table entry %d in: ", i);
return(FALSE);
}
for(j = irefsym; j < irefsym + nrefsym; j++){
if(ref_saves[j] != 0)
break;
}
n = 0;
for(k = j; k < irefsym + nrefsym; k++){
if(ref_saves[k] != 0)
n++;
}
if(n == 0){
if(object->mh != NULL){
mods[i].irefsym = 0;
mods[i].nrefsym = 0;
}
else{
mods64[i].irefsym = 0;
mods64[i].nrefsym = 0;
}
}
else{
if(object->mh != NULL){
mods[i].irefsym = ref_saves[j] - 1;
mods[i].nrefsym = n;
}
else{
mods64[i].irefsym = ref_saves[j] - 1;
mods64[i].nrefsym = n;
}
}
}
new_refs = allocate(new_nextrefsyms * sizeof(struct dylib_reference));
j = 0;
for(i = 0; i < nextrefsyms; i++){
if(ref_saves[i]){
if(saves[refs[i].isym]){
new_refs[j].isym = saves[refs[i].isym] - 1;
new_refs[j].flags = refs[i].flags;
}
else{
if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
new_refs[j].isym = changes[refs[i].isym] - 1;
new_refs[j].flags = refs[i].flags;
}
}
j++;
}
}
new_ntoc = 0;
for(i = 0; i < ntoc; i++){
if(tocs[i].symbol_index >= nsyms){
error_arch(arch, member, "bad symbol index for table of "
"contents table entry %d in: ", i);
return(FALSE);
}
if(saves[tocs[i].symbol_index] != 0 &&
changes[tocs[i].symbol_index] == 0)
new_ntoc++;
}
new_tocs = allocate(new_ntoc * sizeof(struct dylib_table_of_contents));
j = 0;
for(i = 0; i < ntoc; i++){
if(saves[tocs[i].symbol_index] != 0 &&
changes[tocs[i].symbol_index] == 0){
new_tocs[j].symbol_index = saves[tocs[i].symbol_index] - 1;
new_tocs[j].module_index = tocs[i].module_index;
j++;
}
}
#ifdef TRIE_SUPPORT
if(object->dyld_info != NULL &&
object->dyld_info->export_size != 0 &&
(default_dyld_executable || sfile != NULL || Rfile != NULL)){
const char *error_string;
uint32_t trie_new_size;
error_string = prune_trie((uint8_t *)(object->object_addr +
object->dyld_info->export_off),
object->dyld_info->export_size,
prune,
&trie_new_size);
if(error_string != NULL){
error_arch(arch, member, "%s", error_string);
return(FALSE);
}
}
#endif
if(undef_map != NULL)
free(undef_map);
if(undef_map64 != NULL)
free(undef_map64);
if(changes != NULL)
free(changes);
if(sections != NULL)
free(sections);
if(sections64 != NULL)
free(sections64);
if(errors == 0)
return(TRUE);
else
return(FALSE);
}
#ifdef TRIE_SUPPORT
static
int
prune(
const char *name)
{
uint32_t i;
for(i = 0; i < new_nextdefsym; i++){
if(new_symbols != NULL){
if(strcmp(name, new_strings + new_symbols[inew_nextdefsym + i]
.n_un.n_strx) == 0)
return(0);
}
else{
if(strcmp(name, new_strings + new_symbols64[inew_nextdefsym + i]
.n_un.n_strx) == 0)
return(0);
}
}
return(1);
}
#endif
static
void
make_ld_r_object(
struct arch *arch,
struct member *member,
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");
swap_nlist(symbols, nsyms, object->object_byte_sex);
}
else{
if(swap_object_headers(object->mh64, object->load_commands) ==
FALSE)
fatal("internal error: swap_object_headers() failed");
swap_nlist_64(symbols64, nsyms, object->object_byte_sex);
}
swap_indirect_symbols(indirectsyms, nindirectsyms,
object->object_byte_sex);
}
input_file = makestr("/tmp/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/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(Sflag)
add_execute_list("-S");
if(xflag)
add_execute_list("-x");
add_execute_list(input_file);
add_execute_list("-o");
add_execute_list(output_file);
if(sfile != NULL){
add_execute_list("-x");
add_execute_list("-exported_symbols_list");
add_execute_list(sfile);
}
if(Rfile != NULL){
add_execute_list("-unexported_symbols_list");
add_execute_list(Rfile);
}
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");
nsyms = ld_r_archs->object->st->nsyms;
if(ld_r_archs->object->mh != NULL){
symbols = (struct nlist *)
(ld_r_archs->object->object_addr +
ld_r_archs->object->st->symoff);
if(ld_r_archs->object->object_byte_sex != host_byte_sex)
swap_nlist(symbols, nsyms, host_byte_sex);
symbols64 = NULL;
}
else{
symbols = NULL;
symbols64 = (struct nlist_64 *)
(ld_r_archs->object->object_addr +
ld_r_archs->object->st->symoff);
if(ld_r_archs->object->object_byte_sex != host_byte_sex)
swap_nlist_64(symbols64, nsyms, host_byte_sex);
}
strings = ld_r_archs->object->object_addr +
ld_r_archs->object->st->stroff;
strsize = ld_r_archs->object->st->strsize;
if(ld_r_archs->object->dyst != NULL &&
ld_r_archs->object->dyst->nindirectsyms != 0){
nindirectsyms = ld_r_archs->object->dyst->nindirectsyms;
indirectsyms = (uint32_t *)
(ld_r_archs->object->object_addr +
ld_r_archs->object->dyst->indirectsymoff);
if(ld_r_archs->object->object_byte_sex != host_byte_sex)
swap_indirect_symbols(indirectsyms, nindirectsyms,
host_byte_sex);
}
else{
indirectsyms = NULL;
nindirectsyms = 0;
}
if(ld_r_archs->object->mh != NULL)
ld_r_archs->object->input_sym_info_size =
nsyms * sizeof(struct nlist) +
strsize;
else
ld_r_archs->object->input_sym_info_size =
nsyms * sizeof(struct nlist_64) +
strsize;
*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
strip_LC_UUID_commands(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t i, ncmds, nuuids, mh_sizeofcmds, sizeofcmds;
struct load_command *lc1, *lc2, *new_load_commands;
struct segment_command *sg;
nuuids = 0;
lc1 = arch->object->load_commands;
if(arch->object->mh != NULL){
ncmds = arch->object->mh->ncmds;
mh_sizeofcmds = arch->object->mh->sizeofcmds;
}
else{
ncmds = arch->object->mh64->ncmds;
mh_sizeofcmds = arch->object->mh64->sizeofcmds;
}
for(i = 0; i < ncmds; i++){
if(lc1->cmd == LC_UUID){
nuuids++;
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
if(nuuids == 0)
return;
new_load_commands = allocate(mh_sizeofcmds);
memset(new_load_commands, '\0', mh_sizeofcmds);
lc1 = arch->object->load_commands;
lc2 = new_load_commands;
sizeofcmds = 0;
for(i = 0; i < ncmds; i++){
if(lc1->cmd != LC_UUID){
memcpy(lc2, lc1, lc1->cmdsize);
sizeofcmds += lc2->cmdsize;
lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
if(mh_sizeofcmds > sizeofcmds){
memset((char *)arch->object->load_commands + sizeofcmds, '\0',
(mh_sizeofcmds - sizeofcmds));
}
ncmds -= nuuids;
if(arch->object->mh != NULL) {
arch->object->mh->sizeofcmds = sizeofcmds;
arch->object->mh->ncmds = ncmds;
} else {
arch->object->mh64->sizeofcmds = sizeofcmds;
arch->object->mh64->ncmds = ncmds;
}
free(new_load_commands);
lc1 = arch->object->load_commands;
for(i = 0; i < ncmds; i++){
switch(lc1->cmd){
case LC_SYMTAB:
arch->object->st = (struct symtab_command *)lc1;
break;
case LC_DYSYMTAB:
arch->object->dyst = (struct dysymtab_command *)lc1;
break;
case LC_TWOLEVEL_HINTS:
arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
break;
case LC_PREBIND_CKSUM:
arch->object->cs = (struct prebind_cksum_command *)lc1;
break;
case LC_SEGMENT:
sg = (struct segment_command *)lc1;
if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
arch->object->seg_linkedit = sg;
break;
case LC_SEGMENT_SPLIT_INFO:
object->split_info_cmd = (struct linkedit_data_command *)lc1;
break;
case LC_FUNCTION_STARTS:
object->func_starts_info_cmd =
(struct linkedit_data_command *)lc1;
break;
case LC_CODE_SIGNATURE:
object->code_sig_cmd = (struct linkedit_data_command *)lc1;
break;
case LC_DYLD_INFO_ONLY:
case LC_DYLD_INFO:
object->dyld_info = (struct dyld_info_command *)lc1;
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
}
#ifndef NMEDIT
static
void
strip_LC_CODE_SIGNATURE_commands(
struct arch *arch,
struct member *member,
struct object *object)
{
uint32_t i, ncmds, mh_sizeofcmds, sizeofcmds;
struct load_command *lc1, *lc2, *new_load_commands;
struct segment_command *sg;
if(object->code_sig_cmd == NULL)
return;
if(arch->object->mh != NULL){
ncmds = arch->object->mh->ncmds;
mh_sizeofcmds = arch->object->mh->sizeofcmds;
}
else{
ncmds = arch->object->mh64->ncmds;
mh_sizeofcmds = arch->object->mh64->sizeofcmds;
}
new_load_commands = allocate(mh_sizeofcmds);
memset(new_load_commands, '\0', mh_sizeofcmds);
lc1 = arch->object->load_commands;
lc2 = new_load_commands;
sizeofcmds = 0;
for(i = 0; i < ncmds; i++){
if(lc1->cmd != LC_CODE_SIGNATURE){
memcpy(lc2, lc1, lc1->cmdsize);
sizeofcmds += lc2->cmdsize;
lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
if(mh_sizeofcmds > sizeofcmds){
memset((char *)arch->object->load_commands + sizeofcmds, '\0',
(mh_sizeofcmds - sizeofcmds));
}
ncmds -= 1;
if(arch->object->mh != NULL) {
arch->object->mh->sizeofcmds = sizeofcmds;
arch->object->mh->ncmds = ncmds;
} else {
arch->object->mh64->sizeofcmds = sizeofcmds;
arch->object->mh64->ncmds = ncmds;
}
free(new_load_commands);
object->code_sig_cmd = NULL;
lc1 = arch->object->load_commands;
for(i = 0; i < ncmds; i++){
switch(lc1->cmd){
case LC_SYMTAB:
arch->object->st = (struct symtab_command *)lc1;
break;
case LC_DYSYMTAB:
arch->object->dyst = (struct dysymtab_command *)lc1;
break;
case LC_TWOLEVEL_HINTS:
arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
break;
case LC_PREBIND_CKSUM:
arch->object->cs = (struct prebind_cksum_command *)lc1;
break;
case LC_SEGMENT:
sg = (struct segment_command *)lc1;
if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
arch->object->seg_linkedit = sg;
break;
case LC_SEGMENT_SPLIT_INFO:
object->split_info_cmd = (struct linkedit_data_command *)lc1;
break;
case LC_FUNCTION_STARTS:
object->func_starts_info_cmd =
(struct linkedit_data_command *)lc1;
break;
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
object->object_size -= sizeof(struct linkedit_data_command);
if(object->mh != NULL)
object->seg_linkedit->fileoff = sizeof(struct mach_header) +
sizeofcmds;
else
object->seg_linkedit64->fileoff = sizeof(struct mach_header_64) +
sizeofcmds;
}
#endif
static
enum bool
private_extern_reference_by_module(
uint32_t symbol_index,
struct dylib_reference *refs,
uint32_t nextrefsyms)
{
uint32_t i;
for(i = 0; i < nextrefsyms; i++){
if(refs[i].isym == symbol_index){
if(refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
return(TRUE);
}
}
}
return(FALSE);
}
static
enum bool
symbol_pointer_used(
uint32_t symbol_index,
uint32_t *indirectsyms,
uint32_t nindirectsyms)
{
uint32_t i;
for(i = 0; i < nindirectsyms; i++){
if(indirectsyms[i] == symbol_index)
return(TRUE);
}
return(FALSE);
}
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));
}
static
int
cmp_qsort_undef_map_64(
const struct undef_map64 *sym1,
const struct undef_map64 *sym2)
{
return(strcmp(qsort_strings + sym1->symbol64.n_un.n_strx,
qsort_strings + sym2->symbol64.n_un.n_strx));
}
#endif
#ifndef NMEDIT
static
int
cmp_qsort_filename(
const char **name1,
const char **name2)
{
return(strcmp(*name1, *name2));
}
static
int
cmp_bsearch_filename(
const char *name1,
const char **name2)
{
return(strcmp(name1, *name2));
}
#endif
#ifdef NMEDIT
static
enum bool
edit_symtab(
struct arch *arch,
struct member *member,
struct object *object,
struct nlist *symbols,
struct nlist_64 *symbols64,
uint32_t nsyms,
char *strings,
uint32_t strsize,
struct dylib_table_of_contents *tocs,
uint32_t ntoc,
struct dylib_module *mods,
struct dylib_module_64 *mods64,
uint32_t nmodtab,
struct dylib_reference *refs,
uint32_t nextrefsyms)
{
uint32_t i, j, k;
unsigned char data_n_sect, nsects;
struct load_command *lc;
struct segment_command *sg;
struct segment_command_64 *sg64;
struct section *s, **sections;
struct section_64 *s64, **sections64;
uint32_t missing_syms;
struct symbol_list *sp;
struct nlist **global_symbol;
struct nlist_64 **global_symbol64;
enum bool global_symbol_found;
char *global_name, save_char;
enum bool dwarf_debug_map;
enum byte_sex host_byte_sex;
int32_t missing_reloc_symbols;
enum bool edit_symtab_return;
char *p, *q;
uint32_t new_ext_strsize, len, inew_syms;
struct nlist **changed_globals;
struct nlist_64 **changed_globals64;
uint32_t nchanged_globals;
uint32_t ncmds, s_flags, n_strx, module_name, ilocalsym, nlocalsym;
uint32_t iextdefsym, nextdefsym;
uint8_t n_type, n_sect, global_symbol_n_sect;
uint64_t n_value;
enum bool warned_about_global_coalesced_symbols;
edit_symtab_return = TRUE;
host_byte_sex = get_host_byte_sex();
missing_reloc_symbols = 0;
warned_about_global_coalesced_symbols = FALSE;
if(nmedits != NULL)
free(nmedits);
nmedits = allocate(nsyms * sizeof(enum bool));
for(i = 0; i < nsyms; i++)
nmedits[i] = FALSE;
if(object->mh_filetype == MH_DYLIB && pflag == TRUE){
error_arch(arch, member, "can't use -p with dynamic libraries");
return(FALSE);
}
j = 0;
nsects = 0;
n_sect = 1;
data_n_sect = NO_SECT;
lc = object->load_commands;
if(object->mh != NULL)
ncmds = object->mh->ncmds;
else
ncmds = object->mh64->ncmds;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
nsects += sg->nsects;
for(j = 0; j < sg->nsects; j++){
if(strcmp(s->segname, SEG_DATA) == 0 &&
strcmp(s->sectname, SECT_DATA) == 0 &&
data_n_sect == NO_SECT){
data_n_sect = n_sect;
break;
}
n_sect++;
s++;
}
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
nsects += sg64->nsects;
for(j = 0; j < sg64->nsects; j++){
if(strcmp(s64->segname, SEG_DATA) == 0 &&
strcmp(s64->sectname, SECT_DATA) == 0 &&
data_n_sect == NO_SECT){
data_n_sect = n_sect;
break;
}
n_sect++;
s64++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(object->mh != NULL){
sections = allocate(nsects * sizeof(struct section *));
sections64 = NULL;
}
else{
sections = NULL;
sections64 = allocate(nsects * sizeof(struct section_64 *));
}
nsects = 0;
lc = object->load_commands;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
sections[nsects++] = s++;
}
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
for(j = 0; j < sg64->nsects; j++){
sections64[nsects++] = s64++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
for(i = 0; i < nsave_symbols; i++)
save_symbols[i].sym = NULL;
for(i = 0; i < nremove_symbols; i++)
remove_symbols[i].sym = NULL;
if(member == NULL){
for(i = 0; i < nsave_symbols; i++)
save_symbols[i].seen = FALSE;
for(i = 0; i < nremove_symbols; i++)
remove_symbols[i].seen = FALSE;
}
nchanged_globals = 0;
if(object->mh != NULL){
changed_globals = allocate(nsyms * sizeof(struct nlist *));
changed_globals64 = NULL;
for(i = 0; i < nsyms; i++)
changed_globals[i] = NULL;
}
else{
changed_globals = NULL;
changed_globals64 = allocate(nsyms * sizeof(struct nlist_64 *));
for(i = 0; i < nsyms; i++)
changed_globals64[i] = NULL;
}
new_nsyms = nsyms;
new_nlocalsym = 0;
new_nextdefsym = 0;
new_nundefsym = 0;
new_strsize = sizeof(int32_t);
new_ext_strsize = 0;
for(i = 0; i < nsyms; i++){
len = 0;
s_flags = 0;
if(object->mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
n_sect = symbols[i].n_sect;
if((n_type & N_TYPE) == N_SECT)
s_flags = sections[n_sect - 1]->flags;
n_value = symbols[i].n_value;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
n_sect = symbols64[i].n_sect;
if((n_type & N_TYPE) == N_SECT)
s_flags = sections64[n_sect - 1]->flags;
n_value = symbols64[i].n_value;
}
if(n_strx != 0){
if(n_strx > strsize){
error_arch(arch, member, "bad string index for symbol "
"table entry %u in: ", i);
return(FALSE);
}
len = strlen(strings + n_strx) + 1;
}
if(n_type & N_EXT){
if((n_type & N_TYPE) != N_UNDF &&
(n_type & N_TYPE) != N_PBUD){
if((n_type & N_TYPE) == N_SECT){
if(n_sect > nsects){
error_arch(arch, member, "bad n_sect for symbol "
"table entry %u in: ", i);
return(FALSE);
}
if(((s_flags & SECTION_TYPE) == S_COALESCED) &&
pflag == FALSE &&
object->mh_filetype != MH_OBJECT){
if(warned_about_global_coalesced_symbols == FALSE){
warning_arch(arch, member, "can't make global "
"coalesced symbols (like %s) into static "
"symbols (use ld(1)'s "
"-exported_symbols_list option) in a final "
"linked image: ", strings + n_strx);
warned_about_global_coalesced_symbols = TRUE;
}
new_nextdefsym++;
new_ext_strsize += len;
new_strsize += len;
sp = bsearch(strings + n_strx,
remove_symbols, nremove_symbols,
sizeof(struct symbol_list),
(int (*)(const void *, const void *))
symbol_list_bsearch);
if(sp != NULL){
if(sp->sym != NULL){
error_arch(arch, member, "more than one "
"symbol for: %s found in: ", sp->name);
return(FALSE);
}
else{
if(object->mh != NULL)
sp->sym = &(symbols[i]);
else
sp->sym = &(symbols64[i]);
sp->seen = TRUE;
warning_arch(arch, member, "can't make "
"global coalesced symbol: %s into a "
"static symbol in: ", sp->name);
}
}
sp = bsearch(strings + n_strx,
save_symbols, nsave_symbols,
sizeof(struct symbol_list),
(int (*)(const void *, const void *))
symbol_list_bsearch);
if(sp != NULL){
if(sp->sym != NULL){
error_arch(arch, member, "more than one "
"symbol for: %s found in: ", sp->name);
return(FALSE);
}
else{
if(object->mh != NULL)
sp->sym = &(symbols[i]);
else
sp->sym = &(symbols64[i]);
sp->seen = TRUE;
}
}
continue;
}
}
sp = bsearch(strings + n_strx,
remove_symbols, nremove_symbols,
sizeof(struct symbol_list),
(int (*)(const void *, const void *))
symbol_list_bsearch);
if(sp != NULL){
if(sp->sym != NULL){
error_arch(arch, member, "more than one symbol "
"for: %s found in: ", sp->name);
return(FALSE);
}
else{
if(object->mh != NULL)
sp->sym = &(symbols[i]);
else
sp->sym = &(symbols64[i]);
sp->seen = TRUE;
goto change_symbol;
}
}
else{
if(sfile == NULL){
if((pflag || object->mh_filetype == MH_DYLIB)
&& nremove_symbols == 0)
goto change_symbol;
new_nextdefsym++;
new_ext_strsize += len;
new_strsize += len;
continue;
}
}
sp = bsearch(strings + n_strx,
save_symbols, nsave_symbols,
sizeof(struct symbol_list),
(int (*)(const void *, const void *))
symbol_list_bsearch);
if(sp != NULL){
if(sp->sym != NULL){
error_arch(arch, member, "more than one symbol "
"for: %s found in: ", sp->name);
return(FALSE);
}
else{
if(object->mh != NULL)
sp->sym = &(symbols[i]);
else
sp->sym = &(symbols64[i]);
sp->seen = TRUE;
new_nextdefsym++;
new_ext_strsize += len;
new_strsize += len;
}
}
else{
if(Aflag && n_type == (N_EXT | N_ABS) &&
(n_value != 0 ||
(n_strx != 0 &&
strncmp(strings + n_strx,
".objc_class_name_",
sizeof(".objc_class_name_") - 1) == 0))){
new_nextdefsym++;
new_ext_strsize += len;
new_strsize += len;
}
else{
change_symbol:
if((n_type & N_TYPE) != N_INDR){
nmedits[i] = TRUE;
if(object->mh != NULL)
changed_globals[nchanged_globals++] =
symbols + i;
else
changed_globals64[nchanged_globals++] =
symbols64 + i;
if(pflag){
new_nextdefsym++;
new_ext_strsize += len;
new_strsize += len;
}
else{
new_nlocalsym++;
new_strsize += len;
}
}
else{
new_nextdefsym++;
new_ext_strsize += len;
new_strsize += len;
}
}
}
}
else{
new_nundefsym++;
new_ext_strsize += len;
new_strsize += len;
}
}
else{
new_nlocalsym++;
new_strsize += len;
}
}
for(i = 0; i < nmodtab; i++){
if(object->mh != NULL)
module_name = mods[i].module_name;
else
module_name = mods64[i].module_name;
if(module_name == 0 || module_name > strsize){
error_arch(arch, member, "bad string index for module_name "
"of module table entry %d in: ", i);
return(FALSE);
}
len = strlen(strings + module_name) + 1;
new_strsize += len;
new_ext_strsize += len;
}
if(member == NULL){
missing_syms = 0;
if(iflag == 0){
for(i = 0; i < nsave_symbols; i++){
if(save_symbols[i].sym == NULL){
if(missing_syms == 0){
error_arch(arch, member, "symbols names listed "
"in: %s not in: ", sfile);
missing_syms = 1;
}
fprintf(stderr, "%s\n", save_symbols[i].name);
}
}
for(i = 0; i < nremove_symbols; i++){
if(remove_symbols[i].sym == NULL){
if(missing_syms == 0){
error_arch(arch, member, "symbols names listed "
"in: %s not in: ", Rfile);
missing_syms = 1;
}
fprintf(stderr, "%s\n", remove_symbols[i].name);
}
}
}
}
global_strings = strings;
if(object->mh != NULL)
qsort(changed_globals, nchanged_globals, sizeof(struct nlist *),
(int (*)(const void *, const void *))cmp_qsort_global);
else
qsort(changed_globals64, nchanged_globals,sizeof(struct nlist_64 *),
(int (*)(const void *, const void *))cmp_qsort_global_64);
dwarf_debug_map = FALSE;
for(i = 0; i < nsyms; i++){
uint16_t n_desc;
if(object->mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
n_desc = symbols[i].n_desc;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
n_desc = symbols64[i].n_desc;
}
if(n_type == N_SO)
dwarf_debug_map = FALSE;
else if (n_type == N_OSO)
dwarf_debug_map = n_desc != 0;
else if (dwarf_debug_map && n_type == N_GSYM){
global_name = strings + n_strx;
if(object->mh != NULL){
global_symbol = bsearch(global_name, changed_globals,
nchanged_globals,sizeof(struct nlist *),
(int (*)(const void *, const void *))
cmp_bsearch_global);
if(global_symbol != NULL){
symbols[i].n_type = N_STSYM;
symbols[i].n_sect = (*global_symbol)->n_sect;
symbols[i].n_value = (*global_symbol)->n_value;
}
}
else{
global_symbol64 = bsearch(global_name, changed_globals64,
nchanged_globals,
sizeof(struct nlist_64 *),
(int (*)(const void *, const void *))
cmp_bsearch_global_64);
if(global_symbol64 != NULL){
symbols64[i].n_type = N_STSYM;
symbols64[i].n_sect = (*global_symbol64)->n_sect;
symbols64[i].n_value = (*global_symbol64)->n_value;
}
}
}
else if(! dwarf_debug_map &&
(n_type == N_GSYM || n_type == N_FUN) &&
(n_strx != 0 && strings[n_strx] != '\0')){
global_name = strings + n_strx;
if((global_name[0] == '+' || global_name[0] == '-') &&
global_name[1] == '['){
j = 2;
while(j + n_strx < strsize && global_name[j] != ']')
j++;
if(j + n_strx < strsize && global_name[j] == ']')
j++;
}
else
j = 0;
while(j + n_strx < strsize && global_name[j] != ':')
j++;
if(j + n_strx >= strsize){
error_arch(arch, member, "bad N_STAB symbol name for entry "
"%u (does not contain ':' separating name from type) "
"in: ", i);
return(FALSE);
}
save_char = global_name[j];
global_name[j] = '\0';
global_symbol_found = FALSE;
global_symbol_n_sect = 0;
if(object->mh != NULL){
global_symbol = bsearch(global_name, changed_globals,
nchanged_globals,sizeof(struct nlist *),
(int (*)(const void *, const void *))
cmp_bsearch_global_stab);
global_symbol64 = NULL;
if(global_symbol != NULL){
global_symbol_found = TRUE;
global_symbol_n_sect = (*global_symbol)->n_sect;
}
}
else{
global_symbol64 = bsearch(global_name, changed_globals64,
nchanged_globals,
sizeof(struct nlist_64 *),
(int (*)(const void *, const void *))
cmp_bsearch_global_stab_64);
global_symbol = NULL;
if(global_symbol64 != NULL){
global_symbol_found = TRUE;
global_symbol_n_sect = (*global_symbol64)->n_sect;
}
}
global_name[j] = save_char;
if(global_symbol_found == TRUE){
if(n_type == N_GSYM){
if(global_symbol_n_sect == data_n_sect){
if(object->mh != NULL)
symbols[i].n_type = N_STSYM;
else
symbols64[i].n_type = N_STSYM;
}
else{
if(object->mh != NULL)
symbols[i].n_type = N_FUN;
else
symbols64[i].n_type = N_FUN;
}
if(object->mh != NULL){
symbols[i].n_sect = (*global_symbol)->n_sect;
symbols[i].n_value = (*global_symbol)->n_value;
symbols[i].n_desc = (*global_symbol)->n_desc;
}
else{
symbols64[i].n_sect = (*global_symbol64)->n_sect;
symbols64[i].n_value = (*global_symbol64)->n_value;
symbols64[i].n_desc = (*global_symbol64)->n_desc;
}
if(j + 1 + n_strx >= strsize ||
global_name[j+1] != 'G'){
error_arch(arch, member, "bad N_GSYM symbol name "
"for entry %u (does not have type 'G' after "
"':' in name) in: ", i);
return(FALSE);
}
global_name[j+1] = 'S';
}
else{
if(j + 1 + n_strx >= strsize ||
global_name[j+1] == 'F'){
global_name[j+1] = 'f';
}
}
}
}
}
global_strings = NULL;
if(saves != NULL)
free(saves);
saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
bzero(saves, nsyms * sizeof(int32_t));
if(object->mh != NULL){
new_symbols = (struct nlist *)
allocate(new_nsyms * sizeof(struct nlist));
new_symbols64 = NULL;
}
else{
new_symbols = NULL;
new_symbols64 = (struct nlist_64 *)
allocate(new_nsyms * sizeof(struct nlist_64));
}
new_strsize = rnd(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;
new_nmodtab = nmodtab;
new_ntoc = ntoc;
new_nextrefsyms = nextrefsyms;
if(object->mh_filetype == MH_DYLIB && nmodtab != 0){
if(object->mh != NULL){
new_mods = allocate(nmodtab * sizeof(struct dylib_module));
new_mods64 = NULL;
}
else{
new_mods = NULL;
new_mods64 = allocate(nmodtab * sizeof(struct dylib_module_64));
}
inew_syms = 0;
for(i = 0; i < nmodtab; i++){
if(object->mh != NULL){
new_mods[i].ilocalsym = inew_syms;
new_mods[i].nlocalsym = 0;
ilocalsym = mods[i].ilocalsym;
nlocalsym = mods[i].nlocalsym;
}
else{
new_mods64[i].ilocalsym = inew_syms;
new_mods64[i].nlocalsym = 0;
ilocalsym = mods64[i].ilocalsym;
nlocalsym = mods64[i].nlocalsym;
}
for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
if(object->mh != NULL){
n_strx = symbols[j].n_un.n_strx;
n_type = symbols[j].n_type;
}
else{
n_strx = symbols64[j].n_un.n_strx;
n_type = symbols64[j].n_type;
}
if((n_type & N_EXT) == 0){
if(object->mh != NULL)
new_symbols[inew_syms] = symbols[j];
else
new_symbols64[inew_syms] = symbols64[j];
if(n_strx != 0){
strcpy(q, strings + n_strx);
if(object->mh != NULL)
new_symbols[inew_syms].n_un.n_strx =
q - new_strings;
else
new_symbols64[inew_syms].n_un.n_strx =
q - new_strings;
q += strlen(q) + 1;
}
inew_syms++;
saves[j] = inew_syms;
if(object->mh != NULL)
new_mods[i].nlocalsym++;
else
new_mods64[i].nlocalsym++;
}
}
if(object->mh != NULL){
iextdefsym = mods[i].iextdefsym;
nextdefsym = mods[i].nextdefsym;
}
else{
iextdefsym = mods64[i].iextdefsym;
nextdefsym = mods64[i].nextdefsym;
}
for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
if(object->mh != NULL){
n_strx = symbols[j].n_un.n_strx;
n_type = symbols[j].n_type;
}
else{
n_strx = symbols64[j].n_un.n_strx;
n_type = symbols64[j].n_type;
}
if((n_type & N_EXT) != 0){
if(nmedits[j] == TRUE){
if(object->mh != NULL){
new_symbols[inew_syms] = symbols[j];
new_symbols[inew_syms].n_type |= N_PEXT;
new_symbols[inew_syms].n_type &= ~N_EXT;
}
else{
new_symbols64[inew_syms] = symbols64[j];
new_symbols64[inew_syms].n_type |= N_PEXT;
new_symbols64[inew_syms].n_type &= ~N_EXT;
}
if(n_strx != 0){
strcpy(q, strings + n_strx);
if(object->mh != NULL)
new_symbols[inew_syms].n_un.n_strx =
q - new_strings;
else
new_symbols64[inew_syms].n_un.n_strx =
q - new_strings;
q += strlen(q) + 1;
}
inew_syms++;
saves[j] = inew_syms;
if(object->mh != NULL)
new_mods[i].nlocalsym++;
else
new_mods64[i].nlocalsym++;
}
}
}
}
for(i = 0; i < nmodtab; i++){
if(object->mh != NULL){
new_mods[i].iextdefsym = inew_syms;
new_mods[i].nextdefsym = 0;
iextdefsym = mods[i].iextdefsym;
nextdefsym = mods[i].nextdefsym;
}
else{
new_mods64[i].iextdefsym = inew_syms;
new_mods64[i].nextdefsym = 0;
iextdefsym = mods64[i].iextdefsym;
nextdefsym = mods64[i].nextdefsym;
}
for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
if(object->mh != NULL){
n_strx = symbols[j].n_un.n_strx;
n_type = symbols[j].n_type;
}
else{
n_strx = symbols64[j].n_un.n_strx;
n_type = symbols64[j].n_type;
}
if((n_type & N_EXT) != 0){
if(nmedits[j] == FALSE){
if(object->mh != NULL)
new_symbols[inew_syms] = symbols[j];
else
new_symbols64[inew_syms] = symbols64[j];
if(n_strx != 0){
strcpy(p, strings + n_strx);
if(object->mh != NULL)
new_symbols[inew_syms].n_un.n_strx =
p - new_strings;
else
new_symbols64[inew_syms].n_un.n_strx =
p - new_strings;
p += strlen(p) + 1;
}
inew_syms++;
saves[j] = inew_syms;
if(object->mh != NULL)
new_mods[i].nextdefsym++;
else
new_mods64[i].nextdefsym++;
}
}
}
}
for(i = 0; i < nsyms; i++){
if(object->mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
}
if((n_type & N_EXT) != 0 &&
((n_type & N_TYPE) == N_UNDF ||
(n_type & N_TYPE) == N_PBUD)){
if(object->mh != NULL)
new_symbols[inew_syms] = symbols[i];
else
new_symbols64[inew_syms] = symbols64[i];
if(n_strx != 0){
strcpy(p, strings + n_strx);
if(object->mh != NULL)
new_symbols[inew_syms].n_un.n_strx =
p - new_strings;
else
new_symbols64[inew_syms].n_un.n_strx =
p - new_strings;
p += strlen(p) + 1;
}
inew_syms++;
saves[i] = inew_syms;
}
}
for(i = 0; i < nmodtab; i++){
if(object->mh != NULL){
strcpy(p, strings + mods[i].module_name);
new_mods[i].module_name = p - new_strings;
p += strlen(p) + 1;
new_mods[i].irefsym = mods[i].irefsym;
new_mods[i].nrefsym = mods[i].nrefsym;
new_mods[i].iextrel = mods[i].iextrel;
new_mods[i].nextrel = mods[i].nextrel;
new_mods[i].iinit_iterm = mods[i].iinit_iterm;
new_mods[i].ninit_nterm = mods[i].ninit_nterm;
new_mods[i].objc_module_info_addr =
mods[i].objc_module_info_addr;
new_mods[i].objc_module_info_size =
mods[i].objc_module_info_size;
}
else{
strcpy(p, strings + mods64[i].module_name);
new_mods64[i].module_name = p - new_strings;
p += strlen(p) + 1;
new_mods64[i].irefsym = mods64[i].irefsym;
new_mods64[i].nrefsym = mods64[i].nrefsym;
new_mods64[i].iextrel = mods64[i].iextrel;
new_mods64[i].nextrel = mods64[i].nextrel;
new_mods64[i].iinit_iterm = mods64[i].iinit_iterm;
new_mods64[i].ninit_nterm = mods64[i].ninit_nterm;
new_mods64[i].objc_module_info_addr =
mods64[i].objc_module_info_addr;
new_mods64[i].objc_module_info_size =
mods64[i].objc_module_info_size;
}
}
new_nextrefsyms = nextrefsyms;
new_refs = allocate(new_nextrefsyms *
sizeof(struct dylib_reference));
j = 0;
for(i = 0; i < nextrefsyms; i++){
if(nmedits[refs[i].isym] == TRUE){
if(refs[i].flags == REFERENCE_FLAG_DEFINED)
new_refs[i].flags =
REFERENCE_FLAG_PRIVATE_DEFINED;
else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY)
new_refs[i].flags =
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY)
new_refs[i].flags =
REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY;
else
new_refs[i].flags = refs[i].flags;
}
else{
new_refs[i].flags = refs[i].flags;
}
new_refs[i].isym = saves[refs[i].isym] - 1;
}
new_ntoc = ntoc - nchanged_globals;
new_tocs = allocate(new_ntoc *
sizeof(struct dylib_table_of_contents));
k = 0;
for(i = 0; i < ntoc; i++){
if(tocs[i].symbol_index >= nsyms){
error_arch(arch, member, "bad symbol index for table of "
"contents table entry %d in: ", i);
return(FALSE);
}
if(nmedits[tocs[i].symbol_index] == FALSE){
new_tocs[k].symbol_index = saves[tocs[i].symbol_index] - 1;
new_tocs[k].module_index = tocs[i].module_index;
k++;
}
}
}
else{
inew_syms = 0;
for(i = 0; i < nsyms; i++){
if(object->mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
}
if((n_type & N_EXT) == 0){
if(object->mh != NULL)
new_symbols[inew_syms] = symbols[i];
else
new_symbols64[inew_syms] = symbols64[i];
if(n_strx != 0){
strcpy(q, strings + n_strx);
if(object->mh != NULL)
new_symbols[inew_syms].n_un.n_strx =
q - new_strings;
else
new_symbols64[inew_syms].n_un.n_strx =
q - new_strings;
q += strlen(q) + 1;
}
inew_syms++;
saves[i] = inew_syms;
}
}
if(pflag == FALSE){
for(i = 0; i < nsyms; i++){
if(object->mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
}
if((n_type & N_EXT) != 0){
if(nmedits[i] == TRUE){
if(object->mh != NULL){
new_symbols[inew_syms] = symbols[i];
new_symbols[inew_syms].n_type &= ~N_EXT;
new_symbols[inew_syms].n_desc &= ~N_WEAK_DEF;
}
else{
new_symbols64[inew_syms] = symbols64[i];
new_symbols64[inew_syms].n_type &= ~N_EXT;
new_symbols64[inew_syms].n_desc &= ~N_WEAK_DEF;
}
if(n_strx != 0){
strcpy(q, strings + n_strx);
if(object->mh != NULL)
new_symbols[inew_syms].n_un.n_strx =
q - new_strings;
else
new_symbols64[inew_syms].n_un.n_strx =
q - new_strings;
q += strlen(q) + 1;
}
inew_syms++;
saves[i] = inew_syms;
}
}
}
}
for(i = 0; i < nsyms; i++){
if(object->mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
}
if((n_type & N_EXT) != 0){
if(nmedits[i] == FALSE || pflag == TRUE){
if(object->mh != NULL)
new_symbols[inew_syms] = symbols[i];
else
new_symbols64[inew_syms] = symbols64[i];
if(nmedits[i] == TRUE && pflag == TRUE){
if(object->mh != NULL)
new_symbols[inew_syms].n_type |= N_PEXT;
else
new_symbols64[inew_syms].n_type |= N_PEXT;
}
if(n_strx != 0){
strcpy(p, strings + n_strx);
if(object->mh != NULL)
new_symbols[inew_syms].n_un.n_strx =
p - new_strings;
else
new_symbols64[inew_syms].n_un.n_strx =
p - new_strings;
p += strlen(p) + 1;
}
inew_syms++;
saves[i] = inew_syms;
}
}
}
}
if(sections != NULL)
free(sections);
if(sections64 != NULL)
free(sections64);
if(errors == 0)
return(TRUE);
else
return(FALSE);
}
static
int
cmp_qsort_global(
const struct nlist **sym1,
const struct nlist **sym2)
{
return(strcmp(global_strings + (*sym1)->n_un.n_strx,
global_strings + (*sym2)->n_un.n_strx));
}
static
int
cmp_qsort_global_64(
const struct nlist_64 **sym1,
const struct nlist_64 **sym2)
{
return(strcmp(global_strings + (*sym1)->n_un.n_strx,
global_strings + (*sym2)->n_un.n_strx));
}
static
int
cmp_bsearch_global_stab(
const char *name,
const struct nlist **sym)
{
return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
}
static
int
cmp_bsearch_global_stab_64(
const char *name,
const struct nlist_64 **sym)
{
return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
}
static
int
cmp_bsearch_global(
const char *name,
const struct nlist **sym)
{
return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
}
static
int
cmp_bsearch_global_64(
const char *name,
const struct nlist_64 **sym)
{
return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
}
#endif