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)
+
+
+ - Fixed more bugs introduced in ranlib(1) causing incorrect
+ error messages about table of contents. Radar bug #9475790.
+
+
+Changes since the last release (cctools-803 for
+the 5.29 Mac OS X Xcode 4.1 Developer release)
+
+
+ - Fixed bugs introduced in strip(1) and libtool(1) causing
+ incorrect error messages about table of contents. Radar bug
+ #9505797.
+
+
+Changes since the last release (cctools-802 for
+the 5.29 Mac OS X Xcode 4.1 Developer release)
+
+
+ - Updated ranlib(1) to update table of contents in place when
+ possible. Radar bug #9354605.
+
+
+Changes since the last release (cctools-801 for
+the 5.29 Mac OS X Xcode 4.1 Developer release)
+
+
+ - Fixed a problem with the fast 'nop' ranlib(1) in libtool(1).
+ Radar bug #9418154.
+
+
+Changes since the last release (cctools-800 for
+the 5.29 Mac OS X Xcode 4.1 Developer release)
+
+
+ - Implemented a fast 'nop' ranlib(1) when run right after ar(1)
+ has already run ranlib(1). Radar bug #9354501.
+
+
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