+ uint64_t firstStabNlistFileOffset = symbolTableFileOffset + stabsOffsetStart;
+ uint64_t lastStabNlistFileOffset = symbolTableFileOffset + stabsOffsetEnd;
+ uint64_t firstStabStringFileOffset = stringPoolFileOffset + stabsStringsOffsetStart;
+ uint64_t lastStabStringFileOffset = stringPoolFileOffset + tabsStringsOffsetEnd;
+ if ( log ) fprintf(stderr, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset);
+ if ( log ) fprintf(stderr, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset);
+ if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
+ if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
+ assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
+
+ CC_MD5_CTX md5state;
+ CC_MD5_Init(&md5state);
+ // checksum everything up to first stabs nlist
+ if ( log ) fprintf(stderr, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset);
+ CC_MD5_Update(&md5state, &wholeBuffer[0], firstStabNlistFileOffset);
+ // checkusm everything after last stabs nlist and up to first stabs string
+ if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset, firstStabStringFileOffset);
+ CC_MD5_Update(&md5state, &wholeBuffer[lastStabNlistFileOffset], firstStabStringFileOffset-lastStabNlistFileOffset);
+ // checksum everything after last stabs string to end of file
+ if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset, _fileSize);
+ CC_MD5_Update(&md5state, &wholeBuffer[lastStabStringFileOffset], _fileSize-lastStabStringFileOffset);
+ CC_MD5_Final(digest, &md5state);
+ if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2],
+ digest[3], digest[4], digest[5], digest[6], digest[7]);
+ }
+ else {
+ CC_MD5(wholeBuffer, _fileSize, digest);
+ }
+ // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
+ digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
+ digest[8] = ( digest[8] & 0x3F ) | 0x80;
+ // update buffer with new UUID
+ _headersAndLoadCommandAtom->setUUID(digest);
+ _headersAndLoadCommandAtom->recopyUUIDCommand();
+ }
+}
+
+
+void OutputFile::writeOutputFile(ld::Internal& state)
+{
+ // for UNIX conformance, error if file exists and is not writable
+ if ( (access(_options.outputFilePath(), F_OK) == 0) && (access(_options.outputFilePath(), W_OK) == -1) )
+ throwf("can't write output file: %s", _options.outputFilePath());
+
+ mode_t permissions = 0777;
+ if ( _options.outputKind() == Options::kObjectFile )
+ permissions = 0666;
+ mode_t umask = ::umask(0);
+ ::umask(umask); // put back the original umask
+ permissions &= ~umask;
+ // Calling unlink first assures the file is gone so that open creates it with correct permissions
+ // It also handles the case where __options.outputFilePath() file is not writable but its directory is
+ // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
+ // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
+ struct stat stat_buf;
+ bool outputIsRegularFile = true;
+ if ( stat(_options.outputFilePath(), &stat_buf) != -1 ) {
+ if (stat_buf.st_mode & S_IFREG) {
+ (void)unlink(_options.outputFilePath());
+ } else {
+ outputIsRegularFile = false;
+ }
+ }
+
+ int fd;
+ // Construct a temporary path of the form {outputFilePath}.ld_XXXXXX
+ const char filenameTemplate[] = ".ld_XXXXXX";
+ char tmpOutput[PATH_MAX];
+ uint8_t *wholeBuffer;
+ if (outputIsRegularFile) {
+ strcpy(tmpOutput, _options.outputFilePath());
+ // If the path is too long to add a suffix for a temporary name then
+ // just fall back to using the output path.
+ if (strlen(tmpOutput)+strlen(filenameTemplate) < PATH_MAX) {
+ strcat(tmpOutput, filenameTemplate);
+ fd = mkstemp(tmpOutput);
+ } else {
+ fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);