From 8657a52394259660c8cacd3d48a069a2f8ae54e9 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Wed, 13 May 2015 23:17:05 +0100 Subject: [PATCH] 806 --- cctools/RelNotes/Private_CompilerTools.html | 45 +++- cctools/include/notes | 11 + cctools/include/stuff/ofile.h | 15 ++ cctools/libstuff/breakout.c | 2 +- cctools/libstuff/notes | 25 +++ cctools/libstuff/ofile.c | 179 ++++++++++++++- cctools/misc/libtool.c | 328 ++++++++++++++++++++++------ cctools/misc/notes | 36 +++ cctools/misc/pagestuff.c | 22 +- cctools/otool/main.c | 12 +- cctools/otool/notes | 4 + cctools/otool/ofile_print.c | 7 +- cctools/otool/ofile_print.h | 4 +- 13 files changed, 608 insertions(+), 82 deletions(-) diff --git a/cctools/RelNotes/Private_CompilerTools.html b/cctools/RelNotes/Private_CompilerTools.html index e115e41..5082889 100644 --- a/cctools/RelNotes/Private_CompilerTools.html +++ b/cctools/RelNotes/Private_CompilerTools.html @@ -1,5 +1,5 @@ - + Private Compiler Tools Release Notes @@ -12,7 +12,7 @@ 2011 by Apple, Inc. All Rights Reserved.

Private Mac OS X Xcode 4.1 Developer Release:
-Compiler Tools (cctools-800)

+Compiler Tools (cctools-806)

This file contains release notes for the 5.29 release of the Compiler Tools for the Mac OS X Xcode 4.1 Developer Release. This @@ -30,6 +30,47 @@ file contains information about the following topics:

Notes Specific to Release 5.29 (Mac OS X Xcode 4.1 Developer Release)

+
Changes since the last release (cctools-805 for +the 5.29 Mac OS X Xcode 4.1 Developer release)
+ + + +
Changes since the last release (cctools-803 for +the 5.29 Mac OS X Xcode 4.1 Developer release)
+ + + +
Changes since the last release (cctools-802 for +the 5.29 Mac OS X Xcode 4.1 Developer release)
+ + + +
Changes since the last release (cctools-801 for +the 5.29 Mac OS X Xcode 4.1 Developer release)
+ + + +
Changes since the last release (cctools-800 for +the 5.29 Mac OS X Xcode 4.1 Developer release)
+ + +
Changes since the last release (cctools-799 for the 5.28 Mac OS X Xcode 3.2.3 Developer release)
diff --git a/cctools/include/notes b/cctools/include/notes index 36eb0d5..d156418 100644 --- a/cctools/include/notes +++ b/cctools/include/notes @@ -1,3 +1,14 @@ +Changes for the 5.27 release (the cctools-805 release): +- Added toc_bad field to the ofile struct in "stuff/ofile.h". + Radar bug #9475790. + +Changes for the 5.27 release (the cctools-803 release): +- Added toc_* fields to the ofile struct in "stuff/ofile.h". Radar bug #9354605. + +Changes for the 5.27 release (the cctools-801 release): +- Added the file_mtime field to the ofile struct in "stuff/ofile.h" and the + mtime parameter to ofile_map_from_memory(). Radar bug #9354501. + Changes for the 5.27 release (the cctools-800 release): - Updated comment in before GET_LIBRARY_ORDINAL to include other dynamic library load commands. Radar bug #8723078. diff --git a/cctools/include/stuff/ofile.h b/cctools/include/stuff/ofile.h index a985ec9..b528e6b 100644 --- a/cctools/include/stuff/ofile.h +++ b/cctools/include/stuff/ofile.h @@ -58,6 +58,7 @@ struct ofile { char *file_name; /* pointer to name malloc'ed by ofile_map */ char *file_addr; /* pointer to vm_allocate'ed memory */ uint32_t file_size; /* size of vm_allocate'ed memory */ + uint64_t file_mtime; /* stat(2)'s mtime */ enum ofile_type file_type; /* type of the file */ struct fat_header *fat_header; /* If a fat file these are filled in and */ @@ -70,6 +71,19 @@ struct ofile { /* field is pointing at space malloc'ed */ /* by ofile_map. */ + /* If this structure is currently referencing a thin archive and it has a + table of contents then these are valid and filled in */ + char *toc_addr; /* pointer to the toc contents */ + uint32_t toc_size; /* total size of the toc */ + struct ar_hdr *toc_ar_hdr; /* the archive header for the toc */ + char *toc_name; /* name of toc member */ + uint32_t toc_name_size; /* size of name of toc member */ + struct ranlib *toc_ranlibs; /* ranlib structs */ + uint32_t toc_nranlibs; /* number of ranlib structs */ + char *toc_strings; /* strings of symbol names (for above) */ + uint32_t toc_strsize; /* number of bytes for the strings above */ + enum bool toc_bad; /* the toc needs to be rebuilt */ + /* If this structure is currently referencing an archive member or an object file that is an archive member these are valid and filled in. */ uint32_t member_offset; /* logical offset to the member starting */ @@ -147,6 +161,7 @@ __private_extern__ enum bool ofile_map_from_memory( char *addr, uint32_t size, const char *file_name, + uint64_t mtime, const struct arch_flag *arch_flag, /* can be NULL */ const char *object_name, /* can be NULL */ struct ofile *ofile, diff --git a/cctools/libstuff/breakout.c b/cctools/libstuff/breakout.c index f4bed2d..50fec73 100644 --- a/cctools/libstuff/breakout.c +++ b/cctools/libstuff/breakout.c @@ -78,7 +78,7 @@ enum bool calculate_input_prebind_cksum) * Rely on the ofile_*() routines to do all the checking and only * return valid ofiles files broken out. */ - if(ofile_map_from_memory((char *)membuf, length, filename, NULL, NULL, + if(ofile_map_from_memory((char *)membuf, length, filename, 0,NULL, NULL, ofile, FALSE) == FALSE){ free(ofile); return(NULL); diff --git a/cctools/libstuff/notes b/cctools/libstuff/notes index 13ca40f..20b7591 100644 --- a/cctools/libstuff/notes +++ b/cctools/libstuff/notes @@ -5,6 +5,31 @@ TODO: - Deal with LC_PREPAGE and unknown load commands that don't need to be swapped. +Changes for the 5.27 release (the cctools-806 release): +- Maded more changes to check_archive_toc() only set the new ofile bad_toc + field when the anything is bad about the table of contents. + +Changes for the 5.27 release (the cctools-805 release): +- Changed check_archive_toc() to set the new ofile bad_toc field when the + file offset or string offset of a toc entry is out of range. This will + cause libtool/ranlib to rebuild it. Radar bug #9475790. + +Changes for the 5.27 release (the cctools-804 release): +- Fixed a bug that when check_archive_toc() was geting called when the whole + was not a file is a thin archive it was producing an error when it should + have just not done the checks. Radar bug #9505797. + +Changes for the 5.27 release (the cctools-803 release): +- Changed ofile_first_member() in ofile.c to fill in the added toc_* fields in + the ofile struct. And added a check_archive_toc() routine to make sure + the table of contents offests are valid. Radar bug #9354605. + +Changes for the 5.28 release (the cctools-801 release): +- Changed ofile_map_from_memory() to take an mtime parameter and ofile_map() + to pass it. ofile_map_from_memory() then saves that into the ofile's new + file_mtime field. Changed breakout_mem() in breakout.c to pass 0 as the mtime + parameter. Radar bug #9354501 + Changes for the 5.28 release (the cctools-799 release): - Changed is_llvm_bitcode() in lto.c to check for a filesize of zero and just return since the libLTO API's will crash it handed a empty file. Radar bug diff --git a/cctools/libstuff/ofile.c b/cctools/libstuff/ofile.c index 5c85798..1b96bab 100644 --- a/cctools/libstuff/ofile.c +++ b/cctools/libstuff/ofile.c @@ -120,6 +120,8 @@ static enum check_type check_extend_format_1( struct ar_hdr *ar_hdr, uint32_t size_left, uint32_t *member_name_size); +static enum check_type check_archive_toc( + struct ofile *ofile); static enum check_type check_Mach_O( struct ofile *ofile); static void swap_back_Mach_O( @@ -868,8 +870,8 @@ enum bool archives_with_fat_objects) printf("Modification time = %ld\n", (long int)stat_buf.st_mtime); #endif /* OTOOL */ - return(ofile_map_from_memory(addr, size, file_name, arch_flag, - object_name, ofile, archives_with_fat_objects)); + return(ofile_map_from_memory(addr, size, file_name, stat_buf.st_mtime, + arch_flag, object_name, ofile, archives_with_fat_objects)); } /* @@ -886,6 +888,7 @@ ofile_map_from_memory( char *addr, uint32_t size, const char *file_name, +uint64_t mtime, const struct arch_flag *arch_flag, /* can be NULL */ const char *object_name, /* can be NULL */ struct ofile *ofile, @@ -908,6 +911,7 @@ enum bool archives_with_fat_objects) return(FALSE); ofile->file_addr = addr; ofile->file_size = size; + ofile->file_mtime = mtime; /* Try to figure out what kind of file this is */ @@ -1746,6 +1750,17 @@ struct ofile *ofile) ofile->member_name_size = size_ar_name(ar_hdr); ar_name_size = 0; } + /* Clear these in case there is no table of contents */ + ofile->toc_addr = NULL; + ofile->toc_size = 0; + ofile->toc_ar_hdr = NULL; + ofile->toc_name = NULL; + ofile->toc_name_size = 0; + ofile->toc_ranlibs = NULL; + ofile->toc_nranlibs = 0; + ofile->toc_strings = NULL; + ofile->toc_strsize = 0; + ofile->toc_bad = FALSE; host_byte_sex = get_host_byte_sex(); @@ -1835,6 +1850,19 @@ struct ofile *ofile) if(check_Mach_O(ofile) == CHECK_BAD) goto cleanup; } + if(ofile->member_type == OFILE_UNKNOWN && + (strncmp(ofile->member_name, SYMDEF_SORTED, + sizeof(SYMDEF_SORTED) - 1) == 0 || + strncmp(ofile->member_name, SYMDEF, + sizeof(SYMDEF) - 1) == 0)){ + ofile->toc_addr = ofile->member_addr; + ofile->toc_size = ofile->member_size; + ofile->toc_ar_hdr = ofile->member_ar_hdr; + ofile->toc_name = ofile->member_name; + ofile->toc_name_size = ofile->member_name_size; + if(check_archive_toc(ofile) == CHECK_BAD) + goto cleanup; + } #ifdef LTO_SUPPORT if(ofile->member_type == OFILE_UNKNOWN && strncmp(ofile->member_name, SYMDEF_SORTED, @@ -3123,6 +3151,153 @@ uint32_t *member_name_size) } /* + * check_archive_toc() checks the archive table of contents referenced in the + * thin archive via the ofile for correctness and if bad sets the bad_toc field + * in the ofile struct to TRUE. If not it sets the other toc_* fields that + * ranlib(1) uses to know it can't update the table of contents and doesn't + * have to totally rebuild it. And by this always returning CHECK_GOOD it + * allows otool(1) to print messed up tables of contents for debugging. + */ +static +enum check_type +check_archive_toc( +struct ofile *ofile) +{ + uint32_t i, symdef_length, offset, nranlibs, strsize; + enum byte_sex host_byte_sex, toc_byte_sex; + struct ranlib *ranlibs; + char *strings; + + ofile->toc_ranlibs = NULL; + ofile->toc_nranlibs = 0; + ofile->toc_strings = NULL; + ofile->toc_strsize = 0; + + /* + * Note this can only be called when the whole file is a thin archive. + */ + if(ofile->file_type != OFILE_ARCHIVE) + return(CHECK_GOOD); + + symdef_length = ofile->toc_size; + /* + * The contents of a __.SYMDEF file is begins with a 32-bit word giving + * the size in bytes of ranlib structures which immediately follow, and + * then continues with a string table consisting of a 32-bit word giving + * the number of bytes of strings which follow and then the strings + * themselves. So the smallest valid size is two 32-bit words long. + */ + if(symdef_length < 2 * sizeof(uint32_t)){ + /* + * Size of table of contents for archive too small to be a valid + * table of contents. + */ + ofile->toc_bad = TRUE; + return(CHECK_GOOD); + } + host_byte_sex = get_host_byte_sex(); + toc_byte_sex = get_toc_byte_sex(ofile->file_addr, ofile->file_size); + if(toc_byte_sex == UNKNOWN_BYTE_SEX){ + /* + * Can't determine the byte order of table of contents as it + * contains no Mach-O files. + */ + ofile->toc_bad = TRUE; + return(CHECK_GOOD); + } + offset = 0; + nranlibs = *((uint32_t *)(ofile->toc_addr + offset)); + if(toc_byte_sex != host_byte_sex) + nranlibs = SWAP_INT(nranlibs); + nranlibs = nranlibs / sizeof(struct ranlib); + offset += sizeof(uint32_t); + ranlibs = (struct ranlib *)(ofile->toc_addr + offset); + offset += sizeof(struct ranlib) * nranlibs; + if(nranlibs == 0) + return(CHECK_GOOD); + if(offset - (2 * sizeof(uint32_t)) > symdef_length){ + /* + * Truncated or malformed archive. The ranlib structures in table + * of contents extends past the end of the table of contents. + */ + ofile->toc_bad = TRUE; + return(CHECK_GOOD); + } + strsize = *((uint32_t *)(ofile->toc_addr + offset)); + if(toc_byte_sex != host_byte_sex) + strsize = SWAP_INT(strsize); + offset += sizeof(uint32_t); + strings = ofile->toc_addr + offset; + offset += strsize; + if(offset - (2 * sizeof(uint32_t)) > symdef_length){ + /* + * Truncated or malformed archive. The ranlib strings in table of + * contents extends past the end of the table of contents. + */ + ofile->toc_bad = TRUE; + return(CHECK_GOOD); + } + if(symdef_length == 2 * sizeof(uint32_t)) + return(CHECK_GOOD); + + /* + * Check the string offset and the member offsets of the ranlib structs. + */ + if(toc_byte_sex != host_byte_sex) + swap_ranlib(ranlibs, nranlibs, host_byte_sex); + for(i = 0; i < nranlibs; i++){ + if(ranlibs[i].ran_un.ran_strx >= strsize){ + /* + * Malformed table of contents. The ranlib struct at this index + * has a bad string index field. + */ + ofile->toc_bad = TRUE; + return(CHECK_GOOD); + } + if(ranlibs[i].ran_off >= ofile->file_size){ + /* + * Malformed table of contents. The ranlib struct at this index + * has a bad library member offset field. + */ + ofile->toc_bad = TRUE; + return(CHECK_GOOD); + } + /* + * These should be on 4 byte boundaries because the maximum + * alignment of the header structures and relocation are 4 bytes. + * But this is has to be 2 bytes because that's the way ar(1) has + * worked historicly in the past. Fortunately this works on the + * 68k machines but will have to change when this is on a real + * machine. + */ +#if defined(mc68000) || defined(__i386__) + if(ranlibs[i].ran_off % sizeof(short) != 0){ + /* + * Malformed table of contents. This ranlib struct library + * member offset not a multiple 2 bytes. + */ + ofile->toc_bad = TRUE; + return(CHECK_GOOD); + } +#else + if(ranlibs[i].ran_off % sizeof(uint32_t) != 0){ + /* + * Malformed table of contents. This ranlib struct library + * member offset not a multiple of 4 bytes. + */ + ofile->toc_bad = TRUE; + return(CHECK_GOOD); + } +#endif + } + ofile->toc_ranlibs = ranlibs; + ofile->toc_nranlibs = nranlibs; + ofile->toc_strings = strings; + ofile->toc_strsize = strsize; + return(CHECK_GOOD); +} + +/* * check_Mach_O() checks the object file's mach header and load commands * referenced in the ofile for correctness (this also swaps the mach header * and load commands into the host byte sex if needed). diff --git a/cctools/misc/libtool.c b/cctools/misc/libtool.c index 71835ae..35952af 100644 --- a/cctools/misc/libtool.c +++ b/cctools/misc/libtool.c @@ -220,6 +220,7 @@ struct member { char *input_base_name; /* the base name in the input file */ uint32_t input_base_name_size; /* the size of the base name */ struct ar_hdr *input_ar_hdr; + uint32_t input_member_offset; /* if from a thin archive */ }; static void usage( @@ -240,7 +241,16 @@ static void add_member( static void free_archs( void); static void create_library( - char *output); + char *output, + struct ofile *ofile); +static enum byte_sex get_target_byte_sex( + struct arch *arch, + enum byte_sex host_byte_sex); +static char *put_toc_member( + char *p, + struct arch *arch, + enum byte_sex host_byte_sex, + enum byte_sex target_byte_sex); static void create_dynamic_shared_library( char *output); static void create_dynamic_shared_library_cleanup( @@ -1327,11 +1337,11 @@ void) char resolvedname[MAXPATHLEN]; if(realpath(ofiles[i].file_name, resolvedname) != NULL) - ld_trace("[Logging for XBS] Used static archive: " - "%s\n", resolvedname); + ld_trace("[Logging for XBS] Used static " + "archive: %s\n", resolvedname); else - ld_trace("[Logging for XBS] Used static archive: " - "%s\n", ofiles[i].file_name); + ld_trace("[Logging for XBS] Used static " + "archive: %s\n", ofiles[i].file_name); ld_trace_archive_printed = TRUE; } /* loop through archive */ @@ -1402,8 +1412,9 @@ void) if((flag = ofile_first_member(ofiles + i)) == TRUE){ if(ofiles[i].member_ar_hdr != NULL && strncmp(ofiles[i].member_name, SYMDEF, - sizeof(SYMDEF) - 1) == 0) + sizeof(SYMDEF) - 1) == 0){ flag = ofile_next_member(ofiles + i); + } while(flag == TRUE){ /* incorrect form: archive with fat object members */ if(ofiles[i].member_type == OFILE_FAT){ @@ -1504,7 +1515,7 @@ void) } } if(errors == 0) - create_library(cmd_flags.files[i]); + create_library(cmd_flags.files[i], ofiles + i); if(cmd_flags.nfiles > 1){ ranlib_fat_error: free_archs(); @@ -1514,7 +1525,7 @@ ranlib_fat_error: errors += previous_errors; } if(cmd_flags.ranlib == FALSE && errors == 0) - create_library(cmd_flags.output); + create_library(cmd_flags.output, NULL); /* * Clean-up of ofiles[] and archs could be done here but since this @@ -1985,6 +1996,11 @@ struct ofile *ofile) member->input_ar_hdr = ofile->member_ar_hdr; member->input_base_name = ofile->member_name; member->input_base_name_size = ofile->member_name_size; + member->input_member_offset = ofile->member_offset - + sizeof(struct ar_hdr); + if(strncmp(ofile->member_ar_hdr->ar_name, AR_EFMT1, + sizeof(AR_EFMT1) - 1) == 0) + member->input_member_offset -= ofile->member_name_size; member->ar_hdr = *(ofile->member_ar_hdr); member->member_name = ofile->member_name; @@ -2136,13 +2152,19 @@ void) * create_library() creates a library from the data structure pointed to by * archs into the specified output file. Only when more than one architecture * is in archs will a fat file be created. + * + * In the case of cmd_flags.ranlib == TRUE the ofile may not be NULL if it + * from a thin archive. If so and the toc_* fields are set and we may update + * the table of contents in place if the new one fits where the old table of + * contents was. */ static void create_library( -char *output) +char *output, +struct ofile *ofile) { - uint32_t i, j, k, l, library_size, offset, pad, *time_offsets; + uint32_t i, j, k, library_size, offset, pad, *time_offsets; enum byte_sex target_byte_sex; char *library, *p, *flush_start; kern_return_t r; @@ -2157,7 +2179,7 @@ char *output) #endif struct stat stat_buf; struct ar_hdr toc_ar_hdr; - enum bool some_tocs; + enum bool some_tocs, same_toc, different_offsets; if(narchs == 0){ if(cmd_flags.ranlib == TRUE){ @@ -2233,6 +2255,143 @@ char *output) */ if(cmd_flags.q == TRUE && some_tocs == FALSE) exit(EXIT_SUCCESS); + + /* + * If this is ranlib(1) and we are running in UNIX standard mode and + * the file is not writeable just print and error message and return. + */ + if(cmd_flags.ranlib == TRUE && + get_unix_standard_mode() == TRUE && + access(output, W_OK) == -1){ + system_error("file: %s is not writable", output); + return; + } + + /* + * If this is ranlib(1) and we have a thin archive that has an existing + * table of contents see if we have enough room to update it in place. + * Actually we check to see that we have the exact same number of + * ranlib structs and string size, as this is the most common case that + * the defined global symbols have not changed when rebuilding and it + * will just be the offset to archive members that will have changed. + */ + if(cmd_flags.ranlib == TRUE && narchs == 1 && + ofile != NULL && ofile->toc_addr != NULL && + ofile->toc_bad == FALSE && + archs[0].toc_nranlibs == ofile->toc_nranlibs && + archs[0].toc_strsize == ofile->toc_strsize){ + + /* + * The existing thin archive may not be laid out the same way as + * libtool(1) would do it. As ar(1) does not know to pad things + * so object files are on their natural alignment. So check to + * see if the offsets are not the same and if the alignment is OK. + */ + different_offsets = FALSE; + for(i = 0; i < archs[0].nmembers; i++){ + if(archs[0].members[i].input_member_offset != + archs[0].members[i].offset){ + different_offsets = TRUE; + /* + * For now we will allow alignments of 4 bytes offsets even + * though we would produce 8 byte alignments. + */ + if(archs[0].members[i].input_member_offset % 4 != 0){ + goto fail_to_update_toc_in_place; + } + } + } + + /* + * The time_offsets array records the offsets to the table of + * contents archive header's ar_date fields. In this case we just + * have one since this is a thin file (non-fat) file. + */ + time_offsets = allocate(1 * sizeof(uint32_t)); + /* + * Calculate the offset to the archive header's time field for the + * table of contents. + */ + time_offsets[0] = SARMAG + + ((char *)&toc_ar_hdr.ar_date - (char *)&toc_ar_hdr); + + /* + * If we had different member offsets in the input thin archive + * we adjust the ranlib structs ran_off to use them. + */ + if(different_offsets == TRUE){ + same_toc = FALSE; + for(i = 0; i < archs[0].toc_nranlibs; i++){ + for(j = 0; j < archs[0].nmembers; j++){ + if(archs[0].members[j].offset == + archs[0].toc_ranlibs[i].ran_off){ + archs[0].toc_ranlibs[i].ran_off = + archs[0].members[i].input_member_offset; + break; + } + } + } + } + else{ + /* + * If the new table of contents and the new string table are the + * same as the old then the archive only needs to be "touched" + * and the time field of the toc needs to be updated. + */ + same_toc = TRUE; + for(i = 0; i < archs[0].toc_nranlibs; i++){ + if(archs[0].toc_ranlibs[i].ran_un.ran_strx != + ofile->toc_ranlibs[i].ran_un.ran_strx || + archs[0].toc_ranlibs[i].ran_off != + ofile->toc_ranlibs[i].ran_off){ + same_toc = FALSE; + break; + } + } + if(same_toc == TRUE){ + for(i = 0; i < archs[0].toc_strsize; i++){ + if(archs[0].toc_strings[i] != ofile->toc_strings[i]){ + same_toc = FALSE; + break; + } + } + } + } + + library_size = SARMAG; + if(same_toc == FALSE) + library_size += archs[0].toc_size; + if((r = vm_allocate(mach_task_self(), (vm_address_t *)&library, + library_size, TRUE)) != KERN_SUCCESS) + mach_fatal(r, "can't vm_allocate() buffer for output file: %s " + "of size %u", output, library_size); + + + /* put in the archive magic string in the buffer */ + p = library; + memcpy(p, ARMAG, SARMAG); + p += SARMAG; + + /* put the table of contents in the buffer if needed */ + target_byte_sex = get_target_byte_sex(archs + 0, host_byte_sex); + if(same_toc == FALSE) + p = put_toc_member(p, archs+0, host_byte_sex, target_byte_sex); + + if((fd = open(output, O_WRONLY, 0)) == -1){ + system_error("can't open output file: %s", output); + return; + } + if(write(fd, library, library_size) != (int)library_size){ + system_error("can't write output file: %s", output); + return; + } + if(close(fd) == -1){ + system_fatal("can't close output file: %s", output); + return; + } + goto update_toc_ar_dates; + } +fail_to_update_toc_in_place: /* * This buffer is vm_allocate'ed to make sure all holes are filled with @@ -2247,16 +2406,8 @@ char *output) * Create the output file. The unlink() is done to handle the problem * when the outputfile is not writable but the directory allows the * file to be removed (since the file may not be there the return code - * of the unlink() is ignored). But if this is ranlib(1) and we are - * running in UNIX standard mode and the file is not writeable don't - * do the unlink() just print and error message. + * of the unlink() is ignored). */ - if(cmd_flags.ranlib == TRUE && - get_unix_standard_mode() == TRUE && - access(output, W_OK) == -1){ - system_error("file: %s is not writable", output); - return; - } (void)unlink(output); if((fd = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1){ system_error("can't create output file: %s", output); @@ -2344,59 +2495,20 @@ char *output) /* * Pick the byte sex to write the table of contents in. */ - target_byte_sex = UNKNOWN_BYTE_SEX; - for(j = 0; - j < arch->nmembers && target_byte_sex == UNKNOWN_BYTE_SEX; - j++){ - target_byte_sex = arch->members[j].object_byte_sex; - } - if(target_byte_sex == UNKNOWN_BYTE_SEX) - target_byte_sex = host_byte_sex; + target_byte_sex = get_target_byte_sex(arch, host_byte_sex); /* - * Put in the table of contents member: - * the archive header - * the archive member name (if using a long name) - * a uint32_t for the number of bytes of the ranlib structs - * the ranlib structs - * a uint32_t for the number of bytes of the strings for the - * ranlibs - * the strings for the ranlib structs + * Remember the offset to the archive header's time field for this + * arch's table of contents member. */ time_offsets[i] = (p - library) + ((char *)&toc_ar_hdr.ar_date - (char *)&toc_ar_hdr); - memcpy(p, (char *)&arch->toc_ar_hdr, sizeof(struct ar_hdr)); - p += sizeof(struct ar_hdr); - - if(arch->toc_long_name == TRUE){ - memcpy(p, arch->toc_name, arch->toc_name_size); - p += arch->toc_name_size + - (rnd(sizeof(struct ar_hdr), 8) - - sizeof(struct ar_hdr)); - } - - l = arch->toc_nranlibs * sizeof(struct ranlib); - if(target_byte_sex != host_byte_sex) - l = SWAP_INT(l); - memcpy(p, (char *)&l, sizeof(uint32_t)); - p += sizeof(uint32_t); - - if(target_byte_sex != host_byte_sex) - swap_ranlib(arch->toc_ranlibs, arch->toc_nranlibs, - target_byte_sex); - memcpy(p, (char *)arch->toc_ranlibs, - arch->toc_nranlibs * sizeof(struct ranlib)); - p += arch->toc_nranlibs * sizeof(struct ranlib); - - l = arch->toc_strsize; - if(target_byte_sex != host_byte_sex) - l = SWAP_INT(l); - memcpy(p, (char *)&l, sizeof(uint32_t)); - p += sizeof(uint32_t); - - memcpy(p, (char *)arch->toc_strings, arch->toc_strsize); - p += arch->toc_strsize; + + /* + * Put in the table of contents member in the output buffer. + */ + p = put_toc_member(p, arch, host_byte_sex, target_byte_sex); output_flush(library, library_size, fd, flush_start - library, p - flush_start); @@ -2479,6 +2591,7 @@ char *output) return; } +update_toc_ar_dates: /* * Now that the library is created on the file system it is written * to get the time for the file on that file system. @@ -2544,6 +2657,87 @@ char *output) } /* + * get_target_byte_sex() pick the byte sex to write the table of contents in + * for the arch. + */ +static +enum byte_sex +get_target_byte_sex( +struct arch *arch, +enum byte_sex host_byte_sex) +{ + uint32_t i; + enum byte_sex target_byte_sex; + + target_byte_sex = UNKNOWN_BYTE_SEX; + for(i = 0; + i < arch->nmembers && target_byte_sex == UNKNOWN_BYTE_SEX; + i++){ + target_byte_sex = arch->members[i].object_byte_sex; + } + if(target_byte_sex == UNKNOWN_BYTE_SEX) + target_byte_sex = host_byte_sex; + return(target_byte_sex); +} + +/* + * put_toc_member() put the contents member for arch into the buffer p and + * returns the pointer to the buffer after the table of contents. + * The table of contents member is: + * the archive header + * the archive member name (if using a long name) + * a uint32_t for the number of bytes of the ranlib structs + * the ranlib structs + * a uint32_t for the number of bytes of the strings for the + * ranlibs + * the strings for the ranlib structs + */ +static +char * +put_toc_member( +char *p, +struct arch *arch, +enum byte_sex host_byte_sex, +enum byte_sex target_byte_sex) +{ + uint32_t l; + + memcpy(p, (char *)&arch->toc_ar_hdr, sizeof(struct ar_hdr)); + p += sizeof(struct ar_hdr); + + if(arch->toc_long_name == TRUE){ + memcpy(p, arch->toc_name, arch->toc_name_size); + p += arch->toc_name_size + + (rnd(sizeof(struct ar_hdr), 8) - + sizeof(struct ar_hdr)); + } + + l = arch->toc_nranlibs * sizeof(struct ranlib); + if(target_byte_sex != host_byte_sex) + l = SWAP_INT(l); + memcpy(p, (char *)&l, sizeof(uint32_t)); + p += sizeof(uint32_t); + + if(target_byte_sex != host_byte_sex) + swap_ranlib(arch->toc_ranlibs, arch->toc_nranlibs, + target_byte_sex); + memcpy(p, (char *)arch->toc_ranlibs, + arch->toc_nranlibs * sizeof(struct ranlib)); + p += arch->toc_nranlibs * sizeof(struct ranlib); + + l = arch->toc_strsize; + if(target_byte_sex != host_byte_sex) + l = SWAP_INT(l); + memcpy(p, (char *)&l, sizeof(uint32_t)); + p += sizeof(uint32_t); + + memcpy(p, (char *)arch->toc_strings, arch->toc_strsize); + p += arch->toc_strsize; + + return(p); +} + +/* * output_flush() takes an offset and a size of part of the output library, * known in the comments as the new area, and causes any fully flushed pages to * be written to the library file the new area in combination with previous diff --git a/cctools/misc/notes b/cctools/misc/notes index 59c0542..3b054ab 100644 --- a/cctools/misc/notes +++ b/cctools/misc/notes @@ -9,6 +9,42 @@ To Do: could have been set otherwise and does not print the next line. - Maybe add fat support for segedit(1) +Changes for the 5.29 release (the cctools-805 release): +- Changed create_library() in libtool.c to check the new ofile bad_toc field + and cause it to create a new library when this happens. Radar bug #9475790. + +Changes for the 5.29 release (the cctools-803 release): +- Changed libtool.c when running as ranlib(1) to attempt to update the table + of contents in place for the common case for thin archives. And removed the + the time stamp checking for the "nop" ranlib case, which now ends up with just + "touching" the file and adjusting the timestamps. Radar bug #9354605. + - Factored out existing code into new routines get_target_byte_sex() and + put_toc_member(). + - Changed process() and removed the time stamp checking for the "nop" ranlib + case. + - Added the input_member_offset field to the struct member and added code to + set its value in add_member(). + - Changed create_library() to take an ofile which is non-NULL if run as + ranlib(1) and a thin archive. + - Added code in create_library() to update the table of contents in place. + And code to only "touch", write the SARMAG, if the table of contents is + the same. This code has to use the input_member_offset in cases that the + thin input archive would not be same as produced by libtool(1) but still + has member offsets at acceptable alignments. + +Changes for the 5.29 release (the cctools-802 release): +- Fixed a problem with the change to libtool(1) for Radar bug #9354501. It was + not setting toc_uptodate to TRUE and was not doing this only when + cmd_flags.ranlib == TRUE. Radar bug #9418154. + +Changes for the 5.29 release (the cctools-801 release): +- Changed process() in libtool.c to check that the table of contents was up to + date based on the file's time stamp and the table of contents time stamp for + archive files. Then if it ranlib(1) being run do nothing if it is up to date. + Radar bug #9354501. +- Fixed a bug in the error handling of pagestuff(1) when used with the -arch + argument but missing an argument for which page. Radar bug #8979851. + Changes for the 5.28 release (the cctools-798 release): - Added this line to the Makefile: CXX = $(shell xcrun -find -sdk $(SDKROOT) g++) diff --git a/cctools/misc/pagestuff.c b/cctools/misc/pagestuff.c index 3d26a04..b056072 100644 --- a/cctools/misc/pagestuff.c +++ b/cctools/misc/pagestuff.c @@ -131,6 +131,8 @@ enum bool arch_found = FALSE; static struct nlist *sorted_symbols = NULL; static struct nlist_64 *sorted_symbols64 = NULL; +static void usage(void); + static void create_file_parts( char *file_name); static struct file_part *new_file_part( @@ -191,12 +193,8 @@ char *argv[]) struct arch_flag a; progname = argv[0]; - if(argc < 3){ - fprintf(stderr, "Usage: %s mach-o [-arch name] [-p] [-a] " - "pagenumber [pagenumber ...]\n", - progname); - exit(EXIT_FAILURE); - } + if(argc < 3) + usage(); start = 2; if(strcmp(argv[start], "-arch") == 0){ @@ -211,6 +209,8 @@ char *argv[]) } arch_flag = &a; start += 2; + if(argc < 5) + usage(); } create_file_parts(argv[1]); @@ -256,6 +256,16 @@ char *argv[]) static void +usage(void) +{ + fprintf(stderr, "Usage: %s mach-o [-arch name] [-p] [-a] " + "pagenumber [pagenumber ...]\n", + progname); + exit(EXIT_FAILURE); +} + +static +void create_file_parts( char *file_name) { diff --git a/cctools/otool/main.c b/cctools/otool/main.c index d261fce..5238df2 100644 --- a/cctools/otool/main.c +++ b/cctools/otool/main.c @@ -586,9 +586,17 @@ void *cookie) /* cookie is not used */ /* * Archive headers. */ - if(aflag && ofile->member_ar_hdr != NULL) + if(aflag && ofile->member_ar_hdr != NULL){ + uint32_t member_offset; + + member_offset = ofile->member_offset - sizeof(struct ar_hdr); + if(strncmp(ofile->member_ar_hdr->ar_name, AR_EFMT1, + sizeof(AR_EFMT1) - 1) == 0) + member_offset -= ofile->member_name_size; + print_ar_hdr(ofile->member_ar_hdr, ofile->member_name, - ofile->member_name_size, vflag); + ofile->member_name_size, member_offset, vflag, Vflag); + } /* * Archive table of contents. diff --git a/cctools/otool/notes b/cctools/otool/notes index ac69bd4..2700fe1 100644 --- a/cctools/otool/notes +++ b/cctools/otool/notes @@ -4,6 +4,10 @@ TODO: the kernel header and change ofile_print.c to recognize new thread states. Changes for the 5.29 release (the cctools-800 release): +- Added printing archive member offsets when -aV is specified. Radar bug + #9354605. + +Changes for the 5.29 release (the cctools-800 release): - Fixed the arm VCVT (between half-precision and single-precision) instructions encodings. Had the op bit inverted in the table. It should have been: VCVT.F32.F16 , Encoded as op = 1 (aka fcvtshp) diff --git a/cctools/otool/ofile_print.c b/cctools/otool/ofile_print.c index e56f594..474ca7b 100644 --- a/cctools/otool/ofile_print.c +++ b/cctools/otool/ofile_print.c @@ -903,7 +903,9 @@ print_ar_hdr( struct ar_hdr *ar_hdr, char *member_name, uint32_t member_name_size, -enum bool verbose) +uint32_t member_offset, +enum bool verbose, +enum bool print_offset) { int32_t i; uint32_t j, mode; @@ -942,6 +944,9 @@ enum bool verbose) size_buf[sizeof(ar_hdr->ar_size)] = '\0'; + if(print_offset == TRUE) + printf("%u\t", member_offset); + if(verbose == TRUE){ mode = strtoul(mode_buf, &endp, 8); if(*endp != '\0') diff --git a/cctools/otool/ofile_print.h b/cctools/otool/ofile_print.h index 237b26e..bf85acb 100644 --- a/cctools/otool/ofile_print.h +++ b/cctools/otool/ofile_print.h @@ -47,7 +47,9 @@ extern void print_ar_hdr( struct ar_hdr *ar_hdr, char *member_name, uint32_t member_name_size, - enum bool verbose); + uint32_t member_offset, + enum bool verbose, + enum bool print_offset); extern void print_library_toc( struct ar_hdr *toc_ar_hdr, -- 2.11.4.GIT