install_name_tool.c [plain text]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include "stuff/errors.h"
#include "stuff/breakout.h"
#include "stuff/rnd.h"
#include "stuff/allocate.h"
char *progname = NULL;
static void usage(
void);
static void process(
struct arch *archs,
uint32_t narchs);
static void write_on_input(
struct arch *archs,
uint32_t narchs,
char *input);
static void setup_object_symbolic_info(
struct object *object);
static void update_load_commands(
struct arch *arch,
uint32_t *header_size);
static char *id = NULL;
struct changes {
char *old;
char *new;
};
static struct changes *changes = NULL;
static uint32_t nchanges = 0;
struct rpaths {
char *old;
char *new;
enum bool found;
};
static struct rpaths *rpaths = NULL;
static uint32_t nrpaths = 0;
struct add_rpaths {
char *new;
};
static struct add_rpaths *add_rpaths = NULL;
static uint32_t nadd_rpaths = 0;
struct delete_rpaths {
char *old;
enum bool found;
};
static struct delete_rpaths *delete_rpaths = NULL;
static uint32_t ndelete_rpaths = 0;
static uint32_t *arch_header_sizes = NULL;
#undef OUTPUT_OPTION
int
main(
int argc,
char **argv,
char **envp)
{
int i, j;
struct arch *archs;
uint32_t narchs;
char *input;
char *output;
output = NULL;
progname = argv[0];
input = NULL;
archs = NULL;
narchs = 0;
for(i = 1; i < argc; i++){
#ifdef OUTPUT_OPTION
if(strcmp(argv[i], "-o") == 0){
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(output != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
output = argv[i+1];
i++;
}
else
#endif
if(strcmp(argv[i], "-id") == 0){
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(id != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
id = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-change") == 0){
if(i + 2 >= argc){
error("missing argument(s) to: %s option", argv[i]);
usage();
}
changes = reallocate(changes,
sizeof(struct changes) * (nchanges + 1));
changes[nchanges].old = argv[i+1];
changes[nchanges].new = argv[i+2];
nchanges += 1;
i += 2;
}
else if(strcmp(argv[i], "-rpath") == 0){
if(i + 2 >= argc){
error("missing argument(s) to: %s option", argv[i]);
usage();
}
for(j = 0; j < nrpaths; j++){
if(strcmp(rpaths[j].old, argv[i+1]) == 0){
if(strcmp(rpaths[j].new, argv[i+2]) == 0){
error("\"-rpath %s %s\" specified more than once",
argv[i+1], argv[i+2]);
usage();
}
error("can't specify both \"-rpath %s %s\" and "
"\"-rpath %s %s\"", rpaths[j].old, rpaths[j].new,
argv[i+1], argv[i+2]);
usage();
}
if(strcmp(rpaths[j].new, argv[i+1]) == 0 ||
strcmp(rpaths[j].old, argv[i+2]) == 0 ||
strcmp(rpaths[j].new, argv[i+2]) == 0){
error("can't specify both \"-rpath %s %s\" and "
"\"-rpath %s %s\"", rpaths[j].old, rpaths[j].new,
argv[i+1], argv[i+2]);
usage();
}
}
for(j = 0; j < nadd_rpaths; j++){
if(strcmp(add_rpaths[j].new, argv[i+1]) == 0 ||
strcmp(add_rpaths[j].new, argv[i+2]) == 0){
error("can't specify both \"-add_rpath %s\" "
"and \"-rpath %s %s\"", add_rpaths[j].new,
argv[i+1], argv[i+2]);
usage();
}
}
for(j = 0; j < ndelete_rpaths; j++){
if(strcmp(delete_rpaths[j].old, argv[i+1]) == 0 ||
strcmp(delete_rpaths[j].old, argv[i+2]) == 0){
error("can't specify both \"-delete_rpath %s\" "
"and \"-rpath %s %s\"", delete_rpaths[j].old,
argv[i+1], argv[i+2]);
usage();
}
}
rpaths = reallocate(rpaths,
sizeof(struct rpaths) * (nrpaths + 1));
rpaths[nrpaths].old = argv[i+1];
rpaths[nrpaths].new = argv[i+2];
rpaths[nrpaths].found = FALSE;
nrpaths += 1;
i += 2;
}
else if(strcmp(argv[i], "-add_rpath") == 0){
if(i + 1 == argc){
error("missing argument(s) to: %s option", argv[i]);
usage();
}
for(j = 0; j < nadd_rpaths; j++){
if(strcmp(add_rpaths[j].new, argv[i+1]) == 0){
error("\"-add_rpath %s\" specified more than once",
add_rpaths[j].new);
usage();
}
}
for(j = 0; j < nrpaths; j++){
if(strcmp(rpaths[j].old, argv[i+1]) == 0 ||
strcmp(rpaths[j].new, argv[i+1]) == 0){
error("can't specify both \"-rpath %s %s\" and "
"\"-add_rpath %s\"", rpaths[j].old, rpaths[j].new,
argv[i+1]);
usage();
}
}
for(j = 0; j < ndelete_rpaths; j++){
if(strcmp(delete_rpaths[j].old, argv[i+1]) == 0){
error("can't specify both \"-delete_rpath %s\" "
"and \"-add_rpath %s\"", delete_rpaths[j].old,
argv[i+1]);
usage();
}
}
add_rpaths = reallocate(add_rpaths,
sizeof(struct add_rpaths) * (nadd_rpaths + 1));
add_rpaths[nadd_rpaths].new = argv[i+1];
nadd_rpaths += 1;
i += 1;
}
else if(strcmp(argv[i], "-delete_rpath") == 0){
if(i + 1 == argc){
error("missing argument(s) to: %s option", argv[i]);
usage();
}
for(j = 0; j < ndelete_rpaths; j++){
if(strcmp(delete_rpaths[j].old, argv[i+1]) == 0){
error("\"-delete_rpath %s\" specified more than once",
delete_rpaths[j].old);
usage();
}
}
for(j = 0; j < nrpaths; j++){
if(strcmp(rpaths[j].old, argv[i+1]) == 0 ||
strcmp(rpaths[j].new, argv[i+1]) == 0){
error("can't specify both \"-rpath %s %s\" and "
"\"-delete_rpath %s\"", rpaths[j].old,
rpaths[j].new, argv[i+1]);
usage();
}
}
for(j = 0; j < nadd_rpaths; j++){
if(strcmp(add_rpaths[j].new, argv[i+1]) == 0){
error("can't specify both \"-add_rpath %s\" "
"and \"-delete_rpath %s\"", add_rpaths[j].new,
argv[i+1]);
usage();
}
}
delete_rpaths = reallocate(delete_rpaths,
sizeof(struct delete_rpaths) *
(ndelete_rpaths + 1));
delete_rpaths[ndelete_rpaths].old = argv[i+1];
delete_rpaths[ndelete_rpaths].found = FALSE;
ndelete_rpaths += 1;
i += 1;
}
else{
if(input != NULL){
error("more than one input file specified (%s and %s)",
argv[i], input);
usage();
}
input = argv[i];
}
}
if(input == NULL || (id == NULL && nchanges == 0 && nrpaths == 0 &&
nadd_rpaths == 0 && ndelete_rpaths == 0))
usage();
breakout(input, &archs, &narchs, FALSE);
if(errors)
exit(EXIT_FAILURE);
checkout(archs, narchs);
if(errors)
exit(EXIT_FAILURE);
arch_header_sizes = allocate(narchs * sizeof(uint32_t));
process(archs, narchs);
if(errors)
exit(EXIT_FAILURE);
if(output != NULL)
writeout(archs, narchs, output, 0777, TRUE, FALSE, FALSE, NULL);
else
write_on_input(archs, narchs, input);
if(errors)
return(EXIT_FAILURE);
else
return(EXIT_SUCCESS);
}
static
void
usage(
void)
{
fprintf(stderr, "Usage: %s [-change old new] ... [-rpath old new] ... "
"[-add_rpath new] ... [-delete_rpath old] ... "
"[-id name] input"
#ifdef OUTPUT_OPTION
" [-o output]"
#endif
"\n", progname);
exit(EXIT_FAILURE);
}
static
void
process(
struct arch *archs,
uint32_t narchs)
{
uint32_t i;
struct object *object;
for(i = 0; i < narchs; i++){
if(archs[i].type == OFILE_Mach_O){
object = archs[i].object;
if(object->mh_filetype == MH_DYLIB_STUB)
fatal("input file: %s is Mach-O dynamic shared library stub"
" file and can't be changed", archs[i].file_name);
setup_object_symbolic_info(object);
update_load_commands(archs + i, arch_header_sizes + i);
}
else{
error("input file: %s is not a Mach-O file",archs[i].file_name);
return;
}
}
}
static
void
write_on_input(
struct arch *archs,
uint32_t narchs,
char *input)
{
int fd;
uint32_t i, offset, size, headers_size;
char *headers;
struct mach_header *mh;
struct mach_header_64 *mh64;
struct load_command *lc;
enum byte_sex host_byte_sex;
host_byte_sex = get_host_byte_sex();
fd = open(input, O_WRONLY, 0);
if(fd == -1)
system_error("can't open input file: %s for writing", input);
for(i = 0; i < narchs; i++){
if(archs[i].fat_arch != NULL)
offset = archs[i].fat_arch->offset;
else
offset = 0;
if(lseek(fd, offset, SEEK_SET) == -1)
system_error("can't lseek to offset: %u in file: %s for "
"writing", offset, input);
if(archs[i].object->mh != NULL){
headers_size = sizeof(struct mach_header) +
archs[i].object->mh->sizeofcmds;
}
else{
headers_size = sizeof(struct mach_header_64) +
archs[i].object->mh64->sizeofcmds;
}
if(arch_header_sizes[i] > headers_size)
size = arch_header_sizes[i];
else
size = headers_size;
headers = allocate(size);
memset(headers, '\0', size);
if(archs[i].object->mh != NULL){
mh = (struct mach_header *)headers;
lc = (struct load_command *)(headers +
sizeof(struct mach_header));
*mh = *(archs[i].object->mh);
memcpy(lc, archs[i].object->load_commands, mh->sizeofcmds);
if(archs[i].object->object_byte_sex != host_byte_sex)
if(swap_object_headers(mh, lc) == FALSE)
fatal("internal error: swap_object_headers() failed");
}
else{
mh64 = (struct mach_header_64 *)headers;
lc = (struct load_command *)(headers +
sizeof(struct mach_header_64));
*mh64 = *(archs[i].object->mh64);
memcpy(lc, archs[i].object->load_commands, mh64->sizeofcmds);
if(archs[i].object->object_byte_sex != host_byte_sex)
if(swap_object_headers(mh64, lc) == FALSE)
fatal("internal error: swap_object_headers() failed");
}
if(write(fd, headers, size) != (int)size)
system_error("can't write new headers in file: %s", input);
free(headers);
}
if(close(fd) == -1)
system_error("can't close written on input file: %s", input);
}
static
void
setup_object_symbolic_info(
struct object *object)
{
#ifdef OUTPUT_OPTION
if(object->st != NULL && object->st->nsyms != 0){
object->output_symbols = (struct nlist *)
(object->object_addr + object->st->symoff);
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist(object->output_symbols,
object->st->nsyms,
get_host_byte_sex());
object->output_nsymbols = object->st->nsyms;
object->output_strings =
object->object_addr + object->st->stroff;
object->output_strings_size = object->st->strsize;
object->input_sym_info_size =
object->st->nsyms * sizeof(struct nlist) +
object->st->strsize;
object->output_sym_info_size =
object->input_sym_info_size;
}
if(object->dyst != NULL){
object->output_ilocalsym = object->dyst->ilocalsym;
object->output_nlocalsym = object->dyst->nlocalsym;
object->output_iextdefsym = object->dyst->iextdefsym;
object->output_nextdefsym = object->dyst->nextdefsym;
object->output_iundefsym = object->dyst->iundefsym;
object->output_nundefsym = object->dyst->nundefsym;
object->output_loc_relocs = (struct relocation_info *)
(object->object_addr + object->dyst->locreloff);
object->output_ext_relocs = (struct relocation_info *)
(object->object_addr + object->dyst->extreloff);
object->output_indirect_symtab = (uint32_t *)
(object->object_addr + object->dyst->indirectsymoff);
object->output_tocs =
(struct dylib_table_of_contents *)
(object->object_addr + object->dyst->tocoff);
object->output_ntoc = object->dyst->ntoc;
object->output_mods = (struct dylib_module *)
(object->object_addr + object->dyst->modtaboff);
object->output_nmodtab = object->dyst->nmodtab;
object->output_refs = (struct dylib_reference *)
(object->object_addr + object->dyst->extrefsymoff);
object->output_nextrefsyms = object->dyst->nextrefsyms;
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->nindirectsyms *
sizeof(uint32_t) +
object->dyst->ntoc *
sizeof(struct dylib_table_of_contents)+
object->dyst->nmodtab *
sizeof(struct dylib_module) +
object->dyst->nextrefsyms *
sizeof(struct dylib_reference);
object->output_sym_info_size +=
object->dyst->nlocrel *
sizeof(struct relocation_info) +
object->dyst->nextrel *
sizeof(struct relocation_info) +
object->dyst->nindirectsyms *
sizeof(uint32_t) +
object->dyst->ntoc *
sizeof(struct dylib_table_of_contents)+
object->dyst->nmodtab *
sizeof(struct dylib_module) +
object->dyst->nextrefsyms *
sizeof(struct dylib_reference);
if(object->split_info_cmd != NULL){
object->output_split_info_data =
(object->object_addr + object->split_info_cmd->dataoff);
object->output_split_info_data_size =
object->split_info_cmd->datasize;
object->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->output_func_start_info_data =
(object->object_addr + object->func_starts_info_cmd->dataoff);
object->output_func_start_info_data_size =
object->func_starts_info_cmd->datasize;
object->input_sym_info_size +=
object->func_starts_info_cmd->datasize;
object->output_sym_info_size +=
object->func_starts_info_cmd->datasize;
}
if(object->hints_cmd != NULL){
object->output_hints = (struct twolevel_hint *)
(object->object_addr +
object->hints_cmd->offset);
object->input_sym_info_size +=
object->hints_cmd->nhints *
sizeof(struct twolevel_hint);
object->output_sym_info_size +=
object->hints_cmd->nhints *
sizeof(struct twolevel_hint);
}
if(object->code_sig_cmd != NULL){
object->output_code_sig_data = object->object_addr +
object->code_sig_cmd->dataoff;
object->output_code_sig_data_size =
object->code_sig_cmd->datasize;
object->input_sym_info_size =
rnd(object->input_sym_info_size, 16);
object->input_sym_info_size +=
object->code_sig_cmd->datasize;
object->output_sym_info_size =
rnd(object->output_sym_info_size, 16);
object->output_sym_info_size +=
object->code_sig_cmd->datasize;
}
}
#endif
}
static
void
update_load_commands(
struct arch *arch,
uint32_t *header_size)
{
uint32_t i, j, new_sizeofcmds, new_size, linked_modules_size, ncmds,
sizeof_mach_header, cmd_round;
uint64_t low_fileoff;
struct load_command *lc1, *lc2, *new_load_commands;
struct dylib_command *dl_load1, *dl_load2, *dl_id1, *dl_id2;
struct prebound_dylib_command *pbdylib1, *pbdylib2;
char *dylib_name1, *dylib_name2, *arch_name, *linked_modules1,
*linked_modules2, *path1, *path2;
struct segment_command *sg;
struct segment_command_64 *sg64;
struct section *s;
struct section_64 *s64;
struct arch_flag arch_flag;
struct rpath_command *rpath1, *rpath2;
enum bool delete;
if(arch->object->mh != NULL){
new_sizeofcmds = arch->object->mh->sizeofcmds;
ncmds = arch->object->mh->ncmds;
sizeof_mach_header = sizeof(struct mach_header);
cmd_round = 4;
arch_flag.cputype = arch->object->mh->cputype;
arch_flag.cpusubtype = arch->object->mh->cpusubtype;
}
else{
new_sizeofcmds = arch->object->mh64->sizeofcmds;
ncmds = arch->object->mh64->ncmds;
sizeof_mach_header = sizeof(struct mach_header_64);
cmd_round = 8;
arch_flag.cputype = arch->object->mh64->cputype;
arch_flag.cpusubtype = arch->object->mh64->cpusubtype;
}
set_arch_flag_name(&arch_flag);
arch_name = arch_flag.name;
low_fileoff = ULLONG_MAX;
lc1 = arch->object->load_commands;
for(i = 0; i < ncmds; i++){
switch(lc1->cmd){
case LC_ID_DYLIB:
dl_id1 = (struct dylib_command *)lc1;
dylib_name1 = (char *)dl_id1 + dl_id1->dylib.name.offset;
if(id != NULL){
new_size = sizeof(struct dylib_command) +
rnd(strlen(id) + 1, cmd_round);
new_sizeofcmds += (new_size - dl_id1->cmdsize);
}
break;
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_REEXPORT_DYLIB:
case LC_LOAD_UPWARD_DYLIB:
case LC_LAZY_LOAD_DYLIB:
dl_load1 = (struct dylib_command *)lc1;
dylib_name1 = (char *)dl_load1 + dl_load1->dylib.name.offset;
for(j = 0; j < nchanges; j++){
if(strcmp(changes[j].old, dylib_name1) == 0){
new_size = sizeof(struct dylib_command) +
rnd(strlen(changes[j].new) + 1,
cmd_round);
new_sizeofcmds += (new_size - dl_load1->cmdsize);
break;
}
}
break;
case LC_PREBOUND_DYLIB:
pbdylib1 = (struct prebound_dylib_command *)lc1;
dylib_name1 = (char *)pbdylib1 + pbdylib1->name.offset;
for(j = 0; j < nchanges; j++){
if(strcmp(changes[j].old, dylib_name1) == 0){
linked_modules_size = pbdylib1->cmdsize - (
sizeof(struct prebound_dylib_command) +
rnd(strlen(dylib_name1) + 1, cmd_round));
new_size = sizeof(struct prebound_dylib_command) +
rnd(strlen(changes[j].new) + 1,
cmd_round) +
linked_modules_size;
new_sizeofcmds += (new_size - pbdylib1->cmdsize);
break;
}
}
break;
case LC_SEGMENT:
sg = (struct segment_command *)lc1;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
if(sg->nsects != 0){
for(j = 0; j < sg->nsects; j++){
if(s->size != 0 &&
(s->flags & S_ZEROFILL) != S_ZEROFILL &&
(s->flags & S_THREAD_LOCAL_ZEROFILL) !=
S_THREAD_LOCAL_ZEROFILL &&
s->offset < low_fileoff)
low_fileoff = s->offset;
s++;
}
}
else{
if(sg->filesize != 0 && sg->fileoff < low_fileoff)
low_fileoff = sg->fileoff;
}
break;
case LC_SEGMENT_64:
sg64 = (struct segment_command_64 *)lc1;
s64 = (struct section_64 *)
((char *)sg64 + sizeof(struct segment_command_64));
if(sg64->nsects != 0){
for(j = 0; j < sg64->nsects; j++){
if(s64->size != 0 &&
(s64->flags & S_ZEROFILL) != S_ZEROFILL &&
(s64->flags & S_THREAD_LOCAL_ZEROFILL) !=
S_THREAD_LOCAL_ZEROFILL &&
s64->offset < low_fileoff)
low_fileoff = s64->offset;
s64++;
}
}
else{
if(sg64->filesize != 0 && sg64->fileoff < low_fileoff)
low_fileoff = sg64->fileoff;
}
break;
case LC_RPATH:
rpath1 = (struct rpath_command *)lc1;
path1 = (char *)rpath1 + rpath1->path.offset;
for(j = 0; j < nadd_rpaths; j++){
if(strcmp(add_rpaths[j].new, path1) == 0){
error("for: %s (for architecture %s) option "
"\"-add_rpath %s\" would duplicate path, file "
"already has LC_RPATH for: %s", arch->file_name,
arch_name, add_rpaths[j].new, path1);
}
}
for(j = 0; j < nrpaths; j++){
if(strcmp(rpaths[j].old, path1) == 0){
rpaths[j].found = TRUE;
new_size = rnd(sizeof(struct rpath_command) +
strlen(rpaths[j].new) + 1,
cmd_round);
new_sizeofcmds += (new_size - rpath1->cmdsize);
break;
}
}
for(j = 0; j < ndelete_rpaths; j++){
if(strcmp(delete_rpaths[j].old, path1) == 0){
delete_rpaths[j].found = TRUE;
new_sizeofcmds -= rpath1->cmdsize;
break;
}
}
break;
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
for(i = 0; i < ndelete_rpaths; i++){
if(delete_rpaths[i].found == FALSE){
error("no LC_RPATH load command with path: %s found in: "
"%s (for architecture %s), required for specified option "
"\"-delete_rpath %s\"", delete_rpaths[i].old,
arch->file_name, arch_name, delete_rpaths[i].old);
}
}
for(i = 0; i < nrpaths; i++){
if(rpaths[i].found == FALSE){
error("no LC_RPATH load command with path: %s found in: "
"%s (for architecture %s), required for specified option "
"\"-rpath %s %s\"", rpaths[i].old, arch->file_name,
arch_name, rpaths[i].old, rpaths[i].new);
}
}
for(i = 0; i < nadd_rpaths; i++){
new_size = rnd(sizeof(struct rpath_command) +
strlen(add_rpaths[i].new) + 1, cmd_round);
new_sizeofcmds += new_size;
}
if(new_sizeofcmds + sizeof_mach_header > low_fileoff){
error("changing install names or rpaths can't be redone for: %s "
"(for architecture %s) because larger updated load commands "
"do not fit (the program must be relinked, and you may need "
"to use -headerpad or -headerpad_max_install_names)",
arch->file_name, arch_name);
return;
}
new_load_commands = allocate(new_sizeofcmds);
memset(new_load_commands, '\0', new_sizeofcmds);
lc1 = arch->object->load_commands;
lc2 = new_load_commands;
for(i = 0; i < ncmds; i++){
delete = FALSE;
switch(lc1->cmd){
case LC_ID_DYLIB:
if(id != NULL){
memcpy(lc2, lc1, sizeof(struct dylib_command));
dl_id2 = (struct dylib_command *)lc2;
dl_id2->cmdsize = sizeof(struct dylib_command) +
rnd(strlen(id) + 1, cmd_round);
dl_id2->dylib.name.offset = sizeof(struct dylib_command);
dylib_name2 = (char *)dl_id2 + dl_id2->dylib.name.offset;
strcpy(dylib_name2, id);
}
else{
memcpy(lc2, lc1, lc1->cmdsize);
}
break;
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_REEXPORT_DYLIB:
case LC_LOAD_UPWARD_DYLIB:
case LC_LAZY_LOAD_DYLIB:
dl_load1 = (struct dylib_command *)lc1;
dylib_name1 = (char *)dl_load1 + dl_load1->dylib.name.offset;
for(j = 0; j < nchanges; j++){
if(strcmp(changes[j].old, dylib_name1) == 0){
memcpy(lc2, lc1, sizeof(struct dylib_command));
dl_load2 = (struct dylib_command *)lc2;
dl_load2->cmdsize = sizeof(struct dylib_command) +
rnd(strlen(changes[j].new) + 1,
cmd_round);
dl_load2->dylib.name.offset =
sizeof(struct dylib_command);
dylib_name2 = (char *)dl_load2 +
dl_load2->dylib.name.offset;
strcpy(dylib_name2, changes[j].new);
break;
}
}
if(j >= nchanges){
memcpy(lc2, lc1, lc1->cmdsize);
}
break;
case LC_PREBOUND_DYLIB:
pbdylib1 = (struct prebound_dylib_command *)lc1;
dylib_name1 = (char *)pbdylib1 + pbdylib1->name.offset;
for(j = 0; j < nchanges; j++){
if(strcmp(changes[j].old, dylib_name1) == 0){
memcpy(lc2, lc1, sizeof(struct prebound_dylib_command));
pbdylib2 = (struct prebound_dylib_command *)lc2;
linked_modules_size = pbdylib1->cmdsize - (
sizeof(struct prebound_dylib_command) +
rnd(strlen(dylib_name1) + 1, cmd_round));
pbdylib2->cmdsize =
sizeof(struct prebound_dylib_command) +
rnd(strlen(changes[j].new) + 1, cmd_round) +
linked_modules_size;
pbdylib2->name.offset =
sizeof(struct prebound_dylib_command);
dylib_name2 = (char *)pbdylib2 +
pbdylib2->name.offset;
strcpy(dylib_name2, changes[j].new);
pbdylib2->linked_modules.offset =
sizeof(struct prebound_dylib_command) +
rnd(strlen(changes[j].new) + 1, cmd_round);
linked_modules1 = (char *)pbdylib1 +
pbdylib1->linked_modules.offset;
linked_modules2 = (char *)pbdylib2 +
pbdylib2->linked_modules.offset;
memcpy(linked_modules2, linked_modules1,
linked_modules_size);
break;
}
}
if(j >= nchanges){
memcpy(lc2, lc1, lc1->cmdsize);
}
break;
case LC_RPATH:
rpath1 = (struct rpath_command *)lc1;
path1 = (char *)rpath1 + rpath1->path.offset;
for(j = 0; j < ndelete_rpaths; j++){
if(strcmp(delete_rpaths[j].old, path1) == 0){
delete = TRUE;
break;
}
}
if(delete == TRUE)
break;
for(j = 0; j < nrpaths; j++){
if(strcmp(rpaths[j].old, path1) == 0){
memcpy(lc2, lc1, sizeof(struct rpath_command));
rpath2 = (struct rpath_command *)lc2;
rpath2->cmdsize = rnd(sizeof(struct rpath_command) +
strlen(rpaths[j].new) + 1,
cmd_round);
rpath2->path.offset = sizeof(struct rpath_command);
path2 = (char *)rpath2 + rpath2->path.offset;
strcpy(path2, rpaths[j].new);
break;
}
}
if(j >= nrpaths){
memcpy(lc2, lc1, lc1->cmdsize);
}
break;
default:
memcpy(lc2, lc1, lc1->cmdsize);
break;
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
if(delete == FALSE)
lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
}
for(i = 0; i < nadd_rpaths; i++){
rpath2 = (struct rpath_command *)lc2;
rpath2->cmd = LC_RPATH;
rpath2->cmdsize = rnd(sizeof(struct rpath_command) +
strlen(add_rpaths[i].new) + 1,
cmd_round);
rpath2->path.offset = sizeof(struct rpath_command);
path2 = (char *)rpath2 + rpath2->path.offset;
strcpy(path2, add_rpaths[i].new);
}
ncmds += nadd_rpaths;
ncmds -= ndelete_rpaths;
if(arch->object->mh != NULL){
*header_size = sizeof(struct mach_header) +
arch->object->mh->sizeofcmds;
if(new_sizeofcmds < arch->object->mh->sizeofcmds){
memset(((char *)arch->object->load_commands) + new_sizeofcmds,
'\0', arch->object->mh->sizeofcmds - new_sizeofcmds);
}
memcpy(arch->object->load_commands, new_load_commands,
new_sizeofcmds);
arch->object->mh->sizeofcmds = new_sizeofcmds;
arch->object->mh->ncmds = ncmds;
}
else{
*header_size = sizeof(struct mach_header_64) +
arch->object->mh64->sizeofcmds;
if(new_sizeofcmds < arch->object->mh64->sizeofcmds){
memset(((char *)arch->object->load_commands) + new_sizeofcmds,
'\0', arch->object->mh64->sizeofcmds - new_sizeofcmds);
}
memcpy(arch->object->load_commands, new_load_commands,
new_sizeofcmds);
arch->object->mh64->sizeofcmds = new_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_64:
sg64 = (struct segment_command_64 *)lc1;
if(strcmp(sg64->segname, SEG_LINKEDIT) == 0)
arch->object->seg_linkedit64 = sg64;
break;
case LC_CODE_SIGNATURE:
arch->object->code_sig_cmd =
(struct linkedit_data_command *)lc1;
break;
case LC_SEGMENT_SPLIT_INFO:
arch->object->split_info_cmd =
(struct linkedit_data_command *)lc1;
break;
case LC_FUNCTION_STARTS:
arch->object->func_starts_info_cmd =
(struct linkedit_data_command *)lc1;
break;
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
}