]>
Commit | Line | Data |
---|---|---|
d696c285 | 1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
6e880c60 | 2 | * |
c2646906 A |
3 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. |
4 | * | |
5 | * @APPLE_LICENSE_HEADER_START@ | |
d696c285 | 6 | * |
c2646906 A |
7 | * This file contains Original Code and/or Modifications of Original Code |
8 | * as defined in and that are subject to the Apple Public Source License | |
9 | * Version 2.0 (the 'License'). You may not use this file except in | |
10 | * compliance with the License. Please obtain a copy of the License at | |
11 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
12 | * file. | |
d696c285 | 13 | * |
c2646906 A |
14 | * The Original Code and all software distributed under the License are |
15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
19 | * Please see the License for the specific language governing rights and | |
20 | * limitations under the License. | |
d696c285 | 21 | * |
c2646906 A |
22 | * @APPLE_LICENSE_HEADER_END@ |
23 | */ | |
24 | ||
25 | ||
26 | #include <sys/types.h> | |
27 | #include <sys/stat.h> | |
d696c285 | 28 | #include <math.h> |
c2646906 | 29 | #include <fcntl.h> |
6e880c60 | 30 | #include <vector> |
c2646906 A |
31 | |
32 | ||
33 | #include "Options.h" | |
34 | ||
d696c285 | 35 | void throwf(const char* format, ...) |
c2646906 A |
36 | { |
37 | va_list list; | |
38 | char* p; | |
39 | va_start(list, format); | |
40 | vasprintf(&p, format, list); | |
41 | va_end(list); | |
d696c285 | 42 | |
c2646906 A |
43 | const char* t = p; |
44 | throw t; | |
45 | } | |
46 | ||
c2646906 | 47 | Options::Options(int argc, const char* argv[]) |
d696c285 A |
48 | : fOutputFile("a.out"), fArchitecture(0), fOutputKind(kDynamicExecutable), fBindAtLoad(false), |
49 | fStripLocalSymbols(false), fKeepPrivateExterns(false), | |
50 | fInterposable(false), fIgnoreOtherArchFiles(false), fForceSubtypeAll(false), fDeadStrip(kDeadStripOff), | |
51 | fVersionMin(k10_1),fNameSpace(kTwoLevelNameSpace), | |
52 | fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fEntryName("start"), fBaseAddress(0), | |
53 | fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives), | |
54 | fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), fPICTreatment(kError), | |
55 | fWeakReferenceMismatchTreatment(kWeakReferenceMismatchError), fMultiplyDefinedDynamic(kWarning), | |
56 | fMultiplyDefinedUnused(kSuppress), fWarnOnMultiplyDefined(false), fClientName(NULL), | |
57 | fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL), | |
58 | fZeroPageSize(0x1000), fStackSize(0), fStackAddr(0), fExecutableStack(false), fMinimumHeaderPad(0), | |
59 | fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false), fVerbose(false), fKeepRelocations(false), | |
60 | fEmitUUID(true),fWarnStabs(false), | |
61 | fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false) | |
c2646906 A |
62 | { |
63 | this->parsePreCommandLineEnvironmentSettings(); | |
64 | this->parse(argc, argv); | |
65 | this->parsePostCommandLineEnvironmentSettings(); | |
66 | this->checkIllegalOptionCombinations(); | |
67 | } | |
68 | ||
69 | Options::~Options() | |
70 | { | |
71 | } | |
72 | ||
d696c285 | 73 | const ObjectFile::ReaderOptions& Options::readerOptions() |
c2646906 A |
74 | { |
75 | return fReaderOptions; | |
76 | } | |
77 | ||
78 | cpu_type_t Options::architecture() | |
79 | { | |
80 | return fArchitecture; | |
81 | } | |
82 | ||
c2646906 A |
83 | const char* Options::getOutputFilePath() |
84 | { | |
85 | return fOutputFile; | |
86 | } | |
87 | ||
c2646906 A |
88 | std::vector<Options::FileInfo>& Options::getInputFiles() |
89 | { | |
90 | return fInputFiles; | |
91 | } | |
92 | ||
93 | Options::OutputKind Options::outputKind() | |
94 | { | |
95 | return fOutputKind; | |
96 | } | |
97 | ||
98 | bool Options::stripLocalSymbols() | |
99 | { | |
100 | return fStripLocalSymbols; | |
101 | } | |
102 | ||
d696c285 | 103 | bool Options::bindAtLoad() |
c2646906 | 104 | { |
d696c285 | 105 | return fBindAtLoad; |
c2646906 A |
106 | } |
107 | ||
d696c285 | 108 | bool Options::prebind() |
c2646906 | 109 | { |
d696c285 | 110 | return fPrebind; |
c2646906 A |
111 | } |
112 | ||
113 | bool Options::fullyLoadArchives() | |
114 | { | |
115 | return fReaderOptions.fFullyLoadArchives; | |
116 | } | |
117 | ||
118 | Options::NameSpace Options::nameSpace() | |
119 | { | |
120 | return fNameSpace; | |
121 | } | |
122 | ||
123 | const char* Options::installPath() | |
124 | { | |
d696c285 | 125 | if ( fDylibInstallName != NULL ) |
c2646906 A |
126 | return fDylibInstallName; |
127 | else | |
128 | return fOutputFile; | |
129 | } | |
130 | ||
131 | uint32_t Options::currentVersion() | |
132 | { | |
133 | return fDylibCurrentVersion; | |
134 | } | |
135 | ||
136 | uint32_t Options::compatibilityVersion() | |
137 | { | |
138 | return fDylibCompatVersion; | |
139 | } | |
140 | ||
141 | const char* Options::entryName() | |
142 | { | |
143 | return fEntryName; | |
144 | } | |
145 | ||
146 | uint64_t Options::baseAddress() | |
147 | { | |
148 | return fBaseAddress; | |
149 | } | |
150 | ||
151 | bool Options::keepPrivateExterns() | |
152 | { | |
153 | return fKeepPrivateExterns; | |
154 | } | |
155 | ||
156 | bool Options::interposable() | |
157 | { | |
158 | return fInterposable; | |
159 | } | |
160 | ||
161 | bool Options::ignoreOtherArchInputFiles() | |
162 | { | |
163 | return fIgnoreOtherArchFiles; | |
164 | } | |
165 | ||
166 | bool Options::forceCpuSubtypeAll() | |
167 | { | |
168 | return fForceSubtypeAll; | |
169 | } | |
170 | ||
171 | bool Options::traceDylibs() | |
172 | { | |
173 | return fReaderOptions.fTraceDylibs; | |
174 | } | |
175 | ||
176 | bool Options::traceArchives() | |
177 | { | |
178 | return fReaderOptions.fTraceArchives; | |
179 | } | |
180 | ||
181 | Options::UndefinedTreatment Options::undefinedTreatment() | |
182 | { | |
183 | return fUndefinedTreatment; | |
184 | } | |
185 | ||
d696c285 A |
186 | Options::VersionMin Options::macosxVersionMin() |
187 | { | |
188 | return fVersionMin; | |
189 | } | |
190 | ||
c2646906 A |
191 | Options::WeakReferenceMismatchTreatment Options::weakReferenceMismatchTreatment() |
192 | { | |
193 | return fWeakReferenceMismatchTreatment; | |
194 | } | |
195 | ||
d696c285 A |
196 | Options::Treatment Options::multipleDefinitionsInDylibs() |
197 | { | |
198 | return fMultiplyDefinedDynamic; | |
199 | } | |
200 | ||
201 | Options::Treatment Options::overridingDefinitionInDependentDylib() | |
202 | { | |
203 | return fMultiplyDefinedUnused; | |
204 | } | |
205 | ||
206 | bool Options::warnOnMultipleDefinitionsInObjectFiles() | |
207 | { | |
208 | return fWarnOnMultiplyDefined; | |
209 | } | |
210 | ||
c2646906 A |
211 | const char* Options::umbrellaName() |
212 | { | |
213 | return fUmbrellaName; | |
214 | } | |
215 | ||
d696c285 A |
216 | std::vector<const char*>& Options::allowableClients() |
217 | { | |
218 | return fAllowableClients; | |
219 | } | |
220 | ||
221 | const char* Options::clientName() | |
222 | { | |
223 | return fClientName; | |
224 | } | |
225 | ||
c2646906 A |
226 | uint64_t Options::zeroPageSize() |
227 | { | |
228 | return fZeroPageSize; | |
229 | } | |
230 | ||
231 | bool Options::hasCustomStack() | |
232 | { | |
233 | return (fStackSize != 0); | |
234 | } | |
d696c285 | 235 | |
c2646906 A |
236 | uint64_t Options::customStackSize() |
237 | { | |
238 | return fStackSize; | |
239 | } | |
240 | ||
241 | uint64_t Options::customStackAddr() | |
242 | { | |
243 | return fStackAddr; | |
244 | } | |
245 | ||
d696c285 A |
246 | bool Options::hasExecutableStack() |
247 | { | |
248 | return fExecutableStack; | |
249 | } | |
250 | ||
c2646906 A |
251 | std::vector<const char*>& Options::initialUndefines() |
252 | { | |
253 | return fInitialUndefines; | |
254 | } | |
255 | ||
d696c285 A |
256 | std::vector<const char*>& Options::traceSymbols() |
257 | { | |
258 | return fTraceSymbols; | |
259 | } | |
260 | ||
c2646906 A |
261 | const char* Options::initFunctionName() |
262 | { | |
263 | return fInitFunctionName; | |
264 | } | |
265 | ||
d696c285 A |
266 | const char* Options::dotOutputFile() |
267 | { | |
268 | return fDotOutputFile; | |
269 | } | |
270 | ||
c2646906 A |
271 | bool Options::hasExportRestrictList() |
272 | { | |
273 | return (fExportMode != kExportDefault); | |
274 | } | |
275 | ||
276 | uint32_t Options::minimumHeaderPad() | |
277 | { | |
278 | return fMinimumHeaderPad; | |
279 | } | |
280 | ||
281 | std::vector<Options::ExtraSection>& Options::extraSections() | |
282 | { | |
283 | return fExtraSections; | |
284 | } | |
285 | ||
286 | std::vector<Options::SectionAlignment>& Options::sectionAlignments() | |
287 | { | |
288 | return fSectionAlignments; | |
289 | } | |
290 | ||
c2646906 A |
291 | Options::CommonsMode Options::commonsMode() |
292 | { | |
293 | return fCommonsMode; | |
294 | } | |
295 | ||
296 | bool Options::warnCommons() | |
297 | { | |
298 | return fWarnCommons; | |
299 | } | |
300 | ||
d696c285 A |
301 | bool Options::keepRelocations() |
302 | { | |
303 | return fKeepRelocations; | |
304 | } | |
305 | ||
306 | bool Options::emitUUID() | |
307 | { | |
308 | return fEmitUUID; | |
309 | } | |
310 | ||
311 | bool Options::warnStabs() | |
312 | { | |
313 | return fWarnStabs; | |
314 | } | |
315 | ||
316 | const char* Options::executablePath() | |
317 | { | |
318 | return fExecutablePath; | |
319 | } | |
320 | ||
321 | Options::DeadStripMode Options::deadStrip() | |
322 | { | |
323 | return fDeadStrip; | |
324 | } | |
325 | ||
c2646906 A |
326 | bool Options::shouldExport(const char* symbolName) |
327 | { | |
328 | switch (fExportMode) { | |
329 | case kExportSome: | |
330 | return ( fExportSymbols.find(symbolName) != fExportSymbols.end() ); | |
331 | case kDontExportSome: | |
332 | return ( fDontExportSymbols.find(symbolName) == fDontExportSymbols.end() ); | |
333 | case kExportDefault: | |
334 | return true; | |
335 | } | |
336 | throw "internal error"; | |
337 | } | |
338 | ||
c2646906 A |
339 | void Options::parseArch(const char* architecture) |
340 | { | |
341 | if ( architecture == NULL ) | |
342 | throw "-arch must be followed by an architecture string"; | |
343 | if ( strcmp(architecture, "ppc") == 0 ) | |
344 | fArchitecture = CPU_TYPE_POWERPC; | |
345 | else if ( strcmp(architecture, "ppc64") == 0 ) | |
346 | fArchitecture = CPU_TYPE_POWERPC64; | |
347 | else if ( strcmp(architecture, "i386") == 0 ) | |
348 | fArchitecture = CPU_TYPE_I386; | |
d696c285 | 349 | else |
c2646906 A |
350 | throw "-arch followed by unknown architecture name"; |
351 | } | |
352 | ||
353 | bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result) | |
354 | { | |
355 | struct stat statBuffer; | |
d696c285 | 356 | char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8]; |
c2646906 | 357 | sprintf(possiblePath, format, dir, rootName); |
d696c285 A |
358 | bool found = (stat(possiblePath, &statBuffer) == 0); |
359 | if ( fTraceDylibSearching ) | |
360 | printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), possiblePath); | |
361 | if ( found ) { | |
c2646906 A |
362 | result.path = strdup(possiblePath); |
363 | result.fileLen = statBuffer.st_size; | |
d696c285 | 364 | result.modTime = statBuffer.st_mtime; |
c2646906 A |
365 | return true; |
366 | } | |
367 | return false; | |
d696c285 | 368 | } |
c2646906 A |
369 | |
370 | ||
371 | Options::FileInfo Options::findLibrary(const char* rootName) | |
372 | { | |
373 | FileInfo result; | |
374 | const int rootNameLen = strlen(rootName); | |
375 | // if rootName ends in .o there is no .a vs .dylib choice | |
376 | if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) { | |
d696c285 A |
377 | for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); |
378 | it != fLibrarySearchPaths.end(); | |
379 | it++) { | |
c2646906 A |
380 | const char* dir = *it; |
381 | if ( checkForFile("%s/%s", dir, rootName, result) ) | |
382 | return result; | |
383 | } | |
384 | } | |
385 | else { | |
386 | bool lookForDylibs = ( fOutputKind != Options::kDyld); | |
387 | switch ( fLibrarySearchMode ) { | |
d696c285 | 388 | case kSearchAllDirsForDylibsThenAllDirsForArchives: |
c2646906 A |
389 | // first look in all directories for just for dylibs |
390 | if ( lookForDylibs ) { | |
d696c285 A |
391 | for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); |
392 | it != fLibrarySearchPaths.end(); | |
393 | it++) { | |
c2646906 A |
394 | const char* dir = *it; |
395 | if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) ) | |
396 | return result; | |
397 | } | |
398 | } | |
399 | // next look in all directories for just for archives | |
d696c285 A |
400 | for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); |
401 | it != fLibrarySearchPaths.end(); | |
402 | it++) { | |
c2646906 A |
403 | const char* dir = *it; |
404 | if ( checkForFile("%s/lib%s.a", dir, rootName, result) ) | |
405 | return result; | |
406 | } | |
407 | break; | |
408 | ||
409 | case kSearchDylibAndArchiveInEachDir: | |
410 | // look in each directory for just for a dylib then for an archive | |
d696c285 A |
411 | for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); |
412 | it != fLibrarySearchPaths.end(); | |
413 | it++) { | |
c2646906 A |
414 | const char* dir = *it; |
415 | if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) ) | |
416 | return result; | |
417 | if ( checkForFile("%s/lib%s.a", dir, rootName, result) ) | |
418 | return result; | |
419 | } | |
420 | break; | |
421 | } | |
422 | } | |
423 | throwf("library not found for -l%s", rootName); | |
424 | } | |
425 | ||
426 | ||
427 | Options::FileInfo Options::findFramework(const char* rootName) | |
428 | { | |
429 | struct stat statBuffer; | |
430 | const int rootNameLen = strlen(rootName); | |
d696c285 A |
431 | for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); |
432 | it != fFrameworkSearchPaths.end(); | |
433 | it++) { | |
434 | // ??? Shouldn't we be using String here and just initializing it? | |
435 | // ??? Use str.c_str () to pull out the string for the stat call. | |
c2646906 A |
436 | const char* dir = *it; |
437 | char possiblePath[strlen(dir)+2*rootNameLen+20]; | |
438 | strcpy(possiblePath, dir); | |
439 | strcat(possiblePath, "/"); | |
440 | strcat(possiblePath, rootName); | |
441 | strcat(possiblePath, ".framework/"); | |
442 | strcat(possiblePath, rootName); | |
d696c285 A |
443 | bool found = (stat(possiblePath, &statBuffer) == 0); |
444 | if ( fTraceDylibSearching ) | |
445 | printf("[Logging for XBS]%sfound framework: '%s'\n", | |
446 | (found ? " " : " not "), possiblePath); | |
447 | if ( found ) { | |
c2646906 A |
448 | FileInfo result; |
449 | result.path = strdup(possiblePath); | |
450 | result.fileLen = statBuffer.st_size; | |
d696c285 | 451 | result.modTime = statBuffer.st_mtime; |
c2646906 A |
452 | return result; |
453 | } | |
454 | } | |
455 | throwf("framework not found %s", rootName); | |
456 | } | |
457 | ||
6e880c60 | 458 | Options::FileInfo Options::findFile(const char* path) |
c2646906 | 459 | { |
6e880c60 | 460 | FileInfo result; |
c2646906 | 461 | struct stat statBuffer; |
d696c285 | 462 | |
6e880c60 A |
463 | // if absolute path and not a .o file, the use SDK prefix |
464 | if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) { | |
465 | const int pathLen = strlen(path); | |
466 | for (std::vector<const char*>::iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) { | |
d696c285 | 467 | // ??? Shouldn't we be using String here? |
6e880c60 A |
468 | const char* sdkPathDir = *it; |
469 | const int sdkPathDirLen = strlen(sdkPathDir); | |
470 | char possiblePath[sdkPathDirLen+pathLen+4]; | |
471 | strcpy(possiblePath, sdkPathDir); | |
472 | if ( possiblePath[sdkPathDirLen-1] == '/' ) | |
473 | possiblePath[sdkPathDirLen-1] = '\0'; | |
474 | strcat(possiblePath, path); | |
475 | if ( stat(possiblePath, &statBuffer) == 0 ) { | |
476 | result.path = strdup(possiblePath); | |
477 | result.fileLen = statBuffer.st_size; | |
d696c285 | 478 | result.modTime = statBuffer.st_mtime; |
6e880c60 A |
479 | return result; |
480 | } | |
481 | } | |
482 | } | |
483 | // try raw path | |
c2646906 | 484 | if ( stat(path, &statBuffer) == 0 ) { |
c2646906 A |
485 | result.path = strdup(path); |
486 | result.fileLen = statBuffer.st_size; | |
d696c285 | 487 | result.modTime = statBuffer.st_mtime; |
c2646906 A |
488 | return result; |
489 | } | |
d696c285 A |
490 | |
491 | // try @executable_path substitution | |
492 | if ( (strncmp(path, "@executable_path/", 17) == 0) && (fExecutablePath != NULL) ) { | |
493 | char newPath[strlen(fExecutablePath) + strlen(path)]; | |
494 | strcpy(newPath, fExecutablePath); | |
495 | char* addPoint = strrchr(newPath,'/'); | |
496 | if ( addPoint != NULL ) | |
497 | strcpy(&addPoint[1], &path[17]); | |
498 | else | |
499 | strcpy(newPath, &path[17]); | |
500 | if ( stat(newPath, &statBuffer) == 0 ) { | |
501 | result.path = strdup(newPath); | |
502 | result.fileLen = statBuffer.st_size; | |
503 | result.modTime = statBuffer.st_mtime; | |
504 | return result; | |
505 | } | |
506 | } | |
507 | ||
6e880c60 A |
508 | // not found |
509 | throwf("file not found: %s", path); | |
c2646906 A |
510 | } |
511 | ||
6e880c60 | 512 | |
c2646906 A |
513 | void Options::loadFileList(const char* fileOfPaths) |
514 | { | |
515 | FILE* file = fopen(fileOfPaths, "r"); | |
d696c285 | 516 | if ( file == NULL ) |
c2646906 | 517 | throwf("-filelist file not found: %s\n", fileOfPaths); |
d696c285 | 518 | |
c2646906 A |
519 | char path[1024]; |
520 | while ( fgets(path, 1024, file) != NULL ) { | |
521 | path[1023] = '\0'; | |
522 | char* eol = strchr(path, '\n'); | |
523 | if ( eol != NULL ) | |
524 | *eol = '\0'; | |
d696c285 | 525 | |
6e880c60 | 526 | fInputFiles.push_back(findFile(path)); |
c2646906 A |
527 | } |
528 | fclose(file); | |
529 | } | |
530 | ||
531 | ||
532 | void Options::loadExportFile(const char* fileOfExports, const char* option, NameSet& set) | |
533 | { | |
534 | // read in whole file | |
535 | int fd = ::open(fileOfExports, O_RDONLY, 0); | |
536 | if ( fd == -1 ) | |
537 | throwf("can't open %s file: %s", option, fileOfExports); | |
538 | struct stat stat_buf; | |
539 | ::fstat(fd, &stat_buf); | |
540 | char* p = (char*)malloc(stat_buf.st_size); | |
541 | if ( p == NULL ) | |
542 | throwf("can't process %s file: %s", option, fileOfExports); | |
d696c285 | 543 | |
c2646906 A |
544 | if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) |
545 | throwf("can't read %s file: %s", option, fileOfExports); | |
d696c285 | 546 | |
c2646906 | 547 | ::close(fd); |
d696c285 | 548 | |
c2646906 A |
549 | // parse into symbols and add to hash_set |
550 | char * const end = &p[stat_buf.st_size]; | |
551 | enum { lineStart, inSymbol, inComment } state = lineStart; | |
552 | char* symbolStart = NULL; | |
553 | for (char* s = p; s < end; ++s ) { | |
554 | switch ( state ) { | |
d696c285 A |
555 | case lineStart: |
556 | if ( *s =='#' ) { | |
557 | state = inComment; | |
558 | } | |
559 | else if ( !isspace(*s) ) { | |
560 | state = inSymbol; | |
561 | symbolStart = s; | |
562 | } | |
563 | break; | |
564 | case inSymbol: | |
565 | if ( *s == '\n' ) { | |
566 | *s = '\0'; | |
567 | // removing any trailing spaces | |
568 | char* last = s-1; | |
569 | while ( isspace(*last) ) { | |
570 | *last = '\0'; | |
571 | --last; | |
c2646906 | 572 | } |
d696c285 A |
573 | set.insert(symbolStart); |
574 | symbolStart = NULL; | |
575 | state = lineStart; | |
576 | } | |
577 | break; | |
578 | case inComment: | |
579 | if ( *s == '\n' ) | |
580 | state = lineStart; | |
581 | break; | |
582 | } | |
583 | } | |
584 | if ( state == inSymbol ) { | |
585 | fprintf(stderr, "ld64 warning: missing line-end at end of file \"%s\"\n", fileOfExports); | |
586 | int len = end-symbolStart+1; | |
587 | char* temp = new char[len]; | |
588 | strlcpy(temp, symbolStart, len); | |
589 | ||
590 | // remove any trailing spaces | |
591 | char* last = &temp[len-2]; | |
592 | while ( isspace(*last) ) { | |
593 | *last = '\0'; | |
594 | --last; | |
c2646906 | 595 | } |
d696c285 | 596 | set.insert(temp); |
c2646906 | 597 | } |
d696c285 | 598 | |
c2646906 A |
599 | // Note: we do not free() the malloc buffer, because the strings are used by the export-set hash table |
600 | } | |
601 | ||
602 | void Options::setUndefinedTreatment(const char* treatment) | |
603 | { | |
d696c285 | 604 | if ( treatment == NULL ) |
c2646906 A |
605 | throw "-undefined missing [ warning | error | suppress | dynamic_lookup ]"; |
606 | ||
607 | if ( strcmp(treatment, "warning") == 0 ) | |
608 | fUndefinedTreatment = kUndefinedWarning; | |
609 | else if ( strcmp(treatment, "error") == 0 ) | |
610 | fUndefinedTreatment = kUndefinedError; | |
611 | else if ( strcmp(treatment, "suppress") == 0 ) | |
612 | fUndefinedTreatment = kUndefinedSuppress; | |
613 | else if ( strcmp(treatment, "dynamic_lookup") == 0 ) | |
614 | fUndefinedTreatment = kUndefinedDynamicLookup; | |
615 | else | |
616 | throw "invalid option to -undefined [ warning | error | suppress | dynamic_lookup ]"; | |
617 | } | |
618 | ||
d696c285 | 619 | Options::Treatment Options::parseTreatment(const char* treatment) |
c2646906 | 620 | { |
d696c285 A |
621 | if ( treatment == NULL ) |
622 | return kNULL; | |
c2646906 A |
623 | |
624 | if ( strcmp(treatment, "warning") == 0 ) | |
d696c285 A |
625 | return kWarning; |
626 | else if ( strcmp(treatment, "error") == 0 ) | |
627 | return kError; | |
c2646906 | 628 | else if ( strcmp(treatment, "suppress") == 0 ) |
d696c285 A |
629 | return kSuppress; |
630 | else | |
631 | return kInvalid; | |
c2646906 A |
632 | } |
633 | ||
d696c285 A |
634 | void Options::setVersionMin(const char* version) |
635 | { | |
636 | if ( version == NULL ) | |
637 | throw "-macosx_version_min argument missing"; | |
638 | ||
639 | if ( strcmp(version, "10.1") == 0 ) | |
640 | fVersionMin = k10_1; | |
641 | else if ( strcmp(version, "10.2") == 0) | |
642 | fVersionMin = k10_2; | |
643 | else if ( strcmp(version, "10.3") == 0) | |
644 | fVersionMin = k10_3; | |
645 | else if ( strcmp(version, "10.4") == 0) | |
646 | fVersionMin = k10_4; | |
647 | else if ( strcmp(version, "10.5") == 0) | |
648 | fVersionMin = k10_5; | |
c2646906 | 649 | else |
d696c285 | 650 | fprintf(stderr, "ld64: unknown option to -macosx_version_min"); |
c2646906 A |
651 | } |
652 | ||
653 | void Options::setWeakReferenceMismatchTreatment(const char* treatment) | |
654 | { | |
d696c285 | 655 | if ( treatment == NULL ) |
c2646906 A |
656 | throw "-weak_reference_mismatches missing [ error | weak | non-weak ]"; |
657 | ||
658 | if ( strcmp(treatment, "error") == 0 ) | |
659 | fWeakReferenceMismatchTreatment = kWeakReferenceMismatchError; | |
660 | else if ( strcmp(treatment, "weak") == 0 ) | |
661 | fWeakReferenceMismatchTreatment = kWeakReferenceMismatchWeak; | |
662 | else if ( strcmp(treatment, "non-weak") == 0 ) | |
663 | fWeakReferenceMismatchTreatment = kWeakReferenceMismatchNonWeak; | |
664 | else | |
665 | throw "invalid option to -weak_reference_mismatches [ error | weak | non-weak ]"; | |
666 | } | |
667 | ||
668 | Options::CommonsMode Options::parseCommonsTreatment(const char* mode) | |
669 | { | |
d696c285 | 670 | if ( mode == NULL ) |
c2646906 A |
671 | throw "-commons missing [ ignore_dylibs | use_dylibs | error ]"; |
672 | ||
673 | if ( strcmp(mode, "ignore_dylibs") == 0 ) | |
674 | return kCommonsIgnoreDylibs; | |
675 | else if ( strcmp(mode, "use_dylibs") == 0 ) | |
676 | return kCommonsOverriddenByDylibs; | |
677 | else if ( strcmp(mode, "error") == 0 ) | |
678 | return kCommonsConflictsDylibsError; | |
679 | else | |
680 | throw "invalid option to -commons [ ignore_dylibs | use_dylibs | error ]"; | |
681 | } | |
682 | ||
c2646906 A |
683 | void Options::setDylibInstallNameOverride(const char* paths) |
684 | { | |
685 | ||
686 | ||
687 | } | |
688 | ||
c2646906 A |
689 | uint64_t Options::parseAddress(const char* addr) |
690 | { | |
691 | char* endptr; | |
692 | uint64_t result = strtoull(addr, &endptr, 16); | |
693 | return result; | |
694 | } | |
695 | ||
c2646906 | 696 | // |
d696c285 | 697 | // Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz |
c2646906 A |
698 | // |
699 | // | |
700 | uint32_t Options::parseVersionNumber(const char* versionString) | |
701 | { | |
702 | unsigned long x = 0; | |
703 | unsigned long y = 0; | |
704 | unsigned long z = 0; | |
705 | char* end; | |
706 | x = strtoul(versionString, &end, 10); | |
707 | if ( *end == '.' ) { | |
708 | y = strtoul(&end[1], &end, 10); | |
709 | if ( *end == '.' ) { | |
710 | z = strtoul(&end[1], &end, 10); | |
711 | } | |
712 | } | |
713 | if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) ) | |
714 | throwf("malformed version number: %s", versionString); | |
715 | ||
716 | return (x << 16) | ( y << 8 ) | z; | |
717 | } | |
718 | ||
719 | void Options::parseSectionOrderFile(const char* segment, const char* section, const char* path) | |
720 | { | |
721 | fprintf(stderr, "ld64: warning -sectorder not yet supported for 64-bit code\n"); | |
722 | } | |
723 | ||
724 | void Options::addSection(const char* segment, const char* section, const char* path) | |
725 | { | |
726 | if ( strlen(segment) > 16 ) | |
727 | throw "-seccreate segment name max 16 chars"; | |
d696c285 A |
728 | if ( strlen(section) > 16 ) { |
729 | char* tmp = strdup(section); | |
730 | tmp[16] = '\0'; | |
731 | fprintf(stderr, "ld64 warning: -seccreate section name (%s) truncated to 16 chars (%s)\n", section, tmp); | |
732 | section = tmp; | |
733 | } | |
c2646906 A |
734 | |
735 | // read in whole file | |
736 | int fd = ::open(path, O_RDONLY, 0); | |
737 | if ( fd == -1 ) | |
738 | throwf("can't open -sectcreate file: %s", path); | |
739 | struct stat stat_buf; | |
740 | ::fstat(fd, &stat_buf); | |
741 | char* p = (char*)malloc(stat_buf.st_size); | |
742 | if ( p == NULL ) | |
743 | throwf("can't process -sectcreate file: %s", path); | |
744 | if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) | |
745 | throwf("can't read -sectcreate file: %s", path); | |
746 | ::close(fd); | |
d696c285 | 747 | |
c2646906 A |
748 | // record section to create |
749 | ExtraSection info = { segment, section, path, (uint8_t*)p, stat_buf.st_size }; | |
750 | fExtraSections.push_back(info); | |
751 | } | |
752 | ||
753 | void Options::addSectionAlignment(const char* segment, const char* section, const char* alignmentStr) | |
754 | { | |
755 | if ( strlen(segment) > 16 ) | |
756 | throw "-sectalign segment name max 16 chars"; | |
757 | if ( strlen(section) > 16 ) | |
758 | throw "-sectalign section name max 16 chars"; | |
759 | ||
d696c285 | 760 | // argument to -sectalign is a hexadecimal number |
c2646906 A |
761 | char* endptr; |
762 | unsigned long value = strtoul(alignmentStr, &endptr, 16); | |
763 | if ( *endptr != '\0') | |
764 | throw "argument for -sectalign is not a hexadecimal number"; | |
765 | if ( value > 0x8000 ) | |
766 | throw "argument for -sectalign must be less than or equal to 0x8000"; | |
d696c285 A |
767 | if ( value == 0 ) { |
768 | fprintf(stderr, "ld64 warning: zero is not a valid -sectalign\n"); | |
769 | value = 1; | |
770 | } | |
771 | ||
772 | // alignment is power of 2 (e.g. page alignment = 12) | |
773 | uint8_t alignment = (uint8_t)log2(value); | |
774 | ||
775 | if ( (unsigned long)(1 << alignment) != value ) { | |
776 | fprintf(stderr, "ld64 warning: alignment for -sectalign %s %s is not a power of two, using 0x%X\n", | |
777 | segment, section, 1 << alignment); | |
778 | } | |
c2646906 A |
779 | |
780 | SectionAlignment info = { segment, section, alignment }; | |
781 | fSectionAlignments.push_back(info); | |
782 | } | |
783 | ||
d696c285 A |
784 | // |
785 | // Process all command line arguments. | |
786 | // | |
787 | // The only error checking done here is that each option is valid and if it has arguments | |
788 | // that they too are valid. | |
789 | // | |
790 | // The general rule is "last option wins", i.e. if both -bundle and -dylib are specified, | |
791 | // whichever was last on the command line is used. | |
792 | // | |
793 | // Error check for invalid combinations of options is done in checkIllegalOptionCombinations() | |
794 | // | |
c2646906 A |
795 | void Options::parse(int argc, const char* argv[]) |
796 | { | |
797 | // pass one builds search list from -L and -F options | |
798 | this->buildSearchPaths(argc, argv); | |
d696c285 A |
799 | |
800 | // reduce re-allocations | |
801 | fInputFiles.reserve(32); | |
802 | ||
c2646906 A |
803 | // pass two parse all other options |
804 | for(int i=1; i < argc; ++i) { | |
805 | const char* arg = argv[i]; | |
d696c285 | 806 | |
c2646906 | 807 | if ( arg[0] == '-' ) { |
d696c285 A |
808 | |
809 | // Since we don't care about the files passed, just the option names, we do this here. | |
810 | if (fPrintOptions) | |
811 | fprintf (stderr, "[Logging ld64 options]\t%s\n", arg); | |
812 | ||
c2646906 | 813 | if ( (arg[1] == 'L') || (arg[1] == 'F') ) { |
6e880c60 | 814 | // previously handled by buildSearchPaths() |
c2646906 A |
815 | } |
816 | else if ( strcmp(arg, "-arch") == 0 ) { | |
817 | parseArch(argv[++i]); | |
818 | } | |
819 | else if ( strcmp(arg, "-dynamic") == 0 ) { | |
820 | // default | |
821 | } | |
822 | else if ( strcmp(arg, "-static") == 0 ) { | |
823 | fOutputKind = kStaticExecutable; | |
824 | } | |
825 | else if ( strcmp(arg, "-dylib") == 0 ) { | |
826 | fOutputKind = kDynamicLibrary; | |
827 | } | |
828 | else if ( strcmp(arg, "-bundle") == 0 ) { | |
829 | fOutputKind = kDynamicBundle; | |
830 | } | |
831 | else if ( strcmp(arg, "-dylinker") == 0 ) { | |
832 | fOutputKind = kDyld; | |
833 | } | |
834 | else if ( strcmp(arg, "-execute") == 0 ) { | |
835 | if ( fOutputKind != kStaticExecutable ) | |
836 | fOutputKind = kDynamicExecutable; | |
837 | } | |
838 | else if ( strcmp(arg, "-r") == 0 ) { | |
839 | fOutputKind = kObjectFile; | |
840 | } | |
841 | else if ( strcmp(arg, "-o") == 0 ) { | |
842 | fOutputFile = argv[++i]; | |
843 | } | |
844 | else if ( arg[1] == 'l' ) { | |
845 | fInputFiles.push_back(findLibrary(&arg[2])); | |
846 | } | |
d696c285 A |
847 | // This causes a dylib to be weakly bound at |
848 | // link time. This corresponds to weak_import. | |
849 | else if ( strncmp(arg, "-weak-l", 7) == 0 ) { | |
850 | FileInfo info = findLibrary(&arg[7]); | |
c2646906 A |
851 | info.options.fWeakImport = true; |
852 | fInputFiles.push_back(info); | |
853 | } | |
d696c285 A |
854 | // Avoid lazy binding. |
855 | // ??? Deprecate. | |
c2646906 A |
856 | else if ( strcmp(arg, "-bind_at_load") == 0 ) { |
857 | fBindAtLoad = true; | |
858 | } | |
859 | else if ( strcmp(arg, "-twolevel_namespace") == 0 ) { | |
860 | fNameSpace = kTwoLevelNameSpace; | |
861 | } | |
862 | else if ( strcmp(arg, "-flat_namespace") == 0 ) { | |
863 | fNameSpace = kFlatNameSpace; | |
864 | } | |
d696c285 A |
865 | // Also sets a bit to ensure dyld causes everything |
866 | // in the namespace to be flat. | |
867 | // ??? Deprecate | |
c2646906 A |
868 | else if ( strcmp(arg, "-force_flat_namespace") == 0 ) { |
869 | fNameSpace = kForceFlatNameSpace; | |
870 | } | |
d696c285 | 871 | // Similar to --whole-archive. |
c2646906 A |
872 | else if ( strcmp(arg, "-all_load") == 0 ) { |
873 | fReaderOptions.fFullyLoadArchives = true; | |
874 | } | |
d696c285 | 875 | // Similar to --whole-archive, but for all ObjC classes. |
c2646906 A |
876 | else if ( strcmp(arg, "-ObjC") == 0 ) { |
877 | fReaderOptions.fLoadObjcClassesInArchives = true; | |
878 | } | |
d696c285 | 879 | // Library versioning. |
c2646906 A |
880 | else if ( strcmp(arg, "-dylib_compatibility_version") == 0 ) { |
881 | fDylibCompatVersion = parseVersionNumber(argv[++i]); | |
882 | } | |
883 | else if ( strcmp(arg, "-dylib_current_version") == 0 ) { | |
884 | fDylibCurrentVersion = parseVersionNumber(argv[++i]); | |
885 | } | |
886 | else if ( strcmp(arg, "-sectorder") == 0 ) { | |
887 | parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]); | |
888 | i += 3; | |
889 | } | |
d696c285 A |
890 | // ??? Deprecate segcreate. |
891 | // -sectcreate puts whole files into a section in the output. | |
c2646906 A |
892 | else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) { |
893 | addSection(argv[i+1], argv[i+2], argv[i+3]); | |
894 | i += 3; | |
895 | } | |
d696c285 | 896 | // Since we have a full path in binary/library names we need to be able to override it. |
c2646906 A |
897 | else if ( (strcmp(arg, "-dylib_install_name") == 0) || (strcmp(arg, "-dylinker_install_name") == 0) ) { |
898 | fDylibInstallName = argv[++i]; | |
899 | } | |
d696c285 | 900 | // Sets the base address of the output. |
c2646906 A |
901 | else if ( strcmp(arg, "-seg1addr") == 0 ) { |
902 | fBaseAddress = parseAddress(argv[++i]); | |
903 | } | |
904 | else if ( strcmp(arg, "-e") == 0 ) { | |
905 | fEntryName = argv[++i]; | |
906 | } | |
d696c285 | 907 | // Same as -@ from the FSF linker. |
c2646906 A |
908 | else if ( strcmp(arg, "-filelist") == 0 ) { |
909 | loadFileList(argv[++i]); | |
910 | } | |
911 | else if ( strcmp(arg, "-keep_private_externs") == 0 ) { | |
912 | fKeepPrivateExterns = true; | |
913 | } | |
d696c285 | 914 | // ??? Deprecate |
c2646906 A |
915 | else if ( strcmp(arg, "-final_output") == 0 ) { |
916 | ++i; | |
917 | // ignore for now | |
918 | } | |
d696c285 A |
919 | // Ensure that all calls to exported symbols go through lazy pointers. Multi-module |
920 | // just ensures that this happens for cross object file boundaries. | |
c2646906 A |
921 | else if ( (strcmp(arg, "-interposable") == 0) || (strcmp(arg, "-multi_module") == 0)) { |
922 | fInterposable = true; | |
923 | } | |
d696c285 | 924 | // Default for -interposable/-multi_module/-single_module. |
c2646906 A |
925 | else if ( strcmp(arg, "-single_module") == 0 ) { |
926 | fInterposable = false; | |
927 | } | |
928 | else if ( strcmp(arg, "-exported_symbols_list") == 0 ) { | |
929 | if ( fExportMode == kDontExportSome ) | |
930 | throw "can't use -exported_symbols_list and -unexported_symbols_list"; | |
931 | fExportMode = kExportSome; | |
932 | loadExportFile(argv[++i], "-exported_symbols_list", fExportSymbols); | |
933 | } | |
934 | else if ( strcmp(arg, "-unexported_symbols_list") == 0 ) { | |
935 | if ( fExportMode == kExportSome ) | |
936 | throw "can't use -exported_symbols_list and -unexported_symbols_list"; | |
937 | fExportMode = kDontExportSome; | |
938 | loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols); | |
939 | } | |
d696c285 | 940 | // ??? Deprecate |
c2646906 A |
941 | else if ( strcmp(arg, "-no_arch_warnings") == 0 ) { |
942 | fIgnoreOtherArchFiles = true; | |
943 | } | |
944 | else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) { | |
945 | fForceSubtypeAll = true; | |
946 | } | |
d696c285 | 947 | // Similar to -weak-l but uses the absolute path name to the library. |
c2646906 | 948 | else if ( strcmp(arg, "-weak_library") == 0 ) { |
6e880c60 | 949 | FileInfo info = findFile(argv[++i]); |
c2646906 A |
950 | info.options.fWeakImport = true; |
951 | fInputFiles.push_back(info); | |
952 | } | |
953 | else if ( strcmp(arg, "-framework") == 0 ) { | |
954 | fInputFiles.push_back(findFramework(argv[++i])); | |
955 | } | |
956 | else if ( strcmp(arg, "-weak_framework") == 0 ) { | |
957 | FileInfo info = findFramework(argv[++i]); | |
958 | info.options.fWeakImport = true; | |
959 | fInputFiles.push_back(info); | |
960 | } | |
d696c285 | 961 | // ??? Deprecate when we get -Bstatic/-Bdynamic. |
c2646906 A |
962 | else if ( strcmp(arg, "-search_paths_first") == 0 ) { |
963 | fLibrarySearchMode = kSearchDylibAndArchiveInEachDir; | |
964 | } | |
965 | else if ( strcmp(arg, "-undefined") == 0 ) { | |
966 | setUndefinedTreatment(argv[++i]); | |
967 | } | |
d696c285 | 968 | // Debugging output flag. |
c2646906 A |
969 | else if ( strcmp(arg, "-arch_multiple") == 0 ) { |
970 | fMessagesPrefixedWithArchitecture = true; | |
971 | } | |
d696c285 A |
972 | // Specify what to do with relocations in read only |
973 | // sections like .text. Could be errors, warnings, | |
974 | // or suppressed. Currently we do nothing with the | |
975 | // flag. | |
c2646906 | 976 | else if ( strcmp(arg, "-read_only_relocs") == 0 ) { |
d696c285 A |
977 | Treatment temp = parseTreatment(argv[++i]); |
978 | ||
979 | if ( temp == kNULL ) | |
980 | throw "-read_only_relocs missing [ warning | error | suppress ]"; | |
981 | else if ( temp == kInvalid ) | |
982 | throw "invalid option to -read_only_relocs [ warning | error | suppress ]"; | |
c2646906 | 983 | } |
d696c285 A |
984 | // Specifies whether or not there are intra section |
985 | // relocations and what to do when found. Could be | |
986 | // errors, warnings, or suppressed. | |
c2646906 | 987 | else if ( strcmp(arg, "-sect_diff_relocs") == 0 ) { |
d696c285 A |
988 | fPICTreatment = parseTreatment(argv[++i]); |
989 | ||
990 | if ( fPICTreatment == kNULL ) | |
991 | throw "-sect_diff_relocs missing [ warning | error | suppress ]"; | |
992 | else if ( fPICTreatment == kInvalid ) | |
993 | throw "invalid option to -sect_diff_relocs [ warning | error | suppress ]"; | |
c2646906 | 994 | } |
d696c285 A |
995 | // Warn, error or make strong a mismatch between weak |
996 | // and non-weak references. | |
c2646906 A |
997 | else if ( strcmp(arg, "-weak_reference_mismatches") == 0 ) { |
998 | setWeakReferenceMismatchTreatment(argv[++i]); | |
999 | } | |
d696c285 A |
1000 | // For a deployment target of 10.3 and earlier ld64 will |
1001 | // prebind an executable with 0s in all addresses that | |
1002 | // are prebound. This can then be fixed up by update_prebinding | |
1003 | // later. Prebinding is less useful on 10.4 and greater. | |
c2646906 | 1004 | else if ( strcmp(arg, "-prebind") == 0 ) { |
d696c285 | 1005 | fPrebind = true; |
c2646906 A |
1006 | } |
1007 | else if ( strcmp(arg, "-noprebind") == 0 ) { | |
d696c285 | 1008 | fPrebind = false; |
c2646906 | 1009 | } |
d696c285 | 1010 | // ??? Deprecate |
c2646906 | 1011 | else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) { |
d696c285 | 1012 | // Do not handle and suppress warnings always. |
c2646906 | 1013 | } |
d696c285 | 1014 | // ??? Deprecate |
c2646906 | 1015 | else if ( strcmp(arg, "-prebind_all_twolevel_modules") == 0 ) { |
d696c285 | 1016 | // Ignore. |
c2646906 | 1017 | } |
d696c285 | 1018 | // ??? Deprecate |
c2646906 | 1019 | else if ( strcmp(arg, "-noprebind_all_twolevel_modules") == 0 ) { |
d696c285 | 1020 | // Ignore. |
c2646906 | 1021 | } |
d696c285 A |
1022 | // Sets a bit in the main executable only that causes fix_prebinding |
1023 | // not to run. This is always set. | |
c2646906 | 1024 | else if ( strcmp(arg, "-nofixprebinding") == 0 ) { |
d696c285 | 1025 | // Ignore. |
c2646906 | 1026 | } |
d696c285 A |
1027 | // This should probably be deprecated when we respect -L and -F |
1028 | // when searching for libraries. | |
c2646906 A |
1029 | else if ( strcmp(arg, "-dylib_file") == 0 ) { |
1030 | setDylibInstallNameOverride(argv[++i]); | |
1031 | } | |
d696c285 A |
1032 | // Allows us to rewrite full paths to be relocatable based on |
1033 | // the path name of the executable. | |
c2646906 | 1034 | else if ( strcmp(arg, "-executable_path") == 0 ) { |
d696c285 A |
1035 | fExecutablePath = argv[++i]; |
1036 | if ( (fExecutablePath == NULL) || (fExecutablePath[0] == '-') ) | |
1037 | throw "-executable_path missing <path>"; | |
c2646906 | 1038 | } |
d696c285 A |
1039 | // ??? Deprecate |
1040 | // Aligns all segments to the power of 2 boundary specified. | |
c2646906 | 1041 | else if ( strcmp(arg, "-segalign") == 0 ) { |
d696c285 A |
1042 | // Ignore. |
1043 | ++i; | |
c2646906 | 1044 | } |
d696c285 A |
1045 | // Puts a specified segment at a particular address that must |
1046 | // be a multiple of the segment alignment. | |
c2646906 A |
1047 | else if ( strcmp(arg, "-segaddr") == 0 ) { |
1048 | // FIX FIX | |
d696c285 | 1049 | i += 2; |
c2646906 | 1050 | } |
d696c285 | 1051 | // ??? Deprecate when we deprecate split-seg. |
c2646906 | 1052 | else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) { |
d696c285 A |
1053 | // Ignore. |
1054 | ++i; | |
c2646906 | 1055 | } |
d696c285 | 1056 | // ??? Deprecate when we deprecate split-seg. |
c2646906 | 1057 | else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) { |
d696c285 A |
1058 | // Ignore. |
1059 | ++i; | |
c2646906 | 1060 | } |
d696c285 | 1061 | // ??? Deprecate when we get rid of basing at build time. |
c2646906 | 1062 | else if ( strcmp(arg, "-seg_addr_table") == 0 ) { |
d696c285 A |
1063 | // Ignore. |
1064 | ++i; | |
c2646906 | 1065 | } |
d696c285 | 1066 | // ??? Deprecate. |
c2646906 | 1067 | else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) { |
d696c285 A |
1068 | // Ignore. |
1069 | ++i; | |
c2646906 A |
1070 | } |
1071 | else if ( strcmp(arg, "-segprot") == 0 ) { | |
1072 | // FIX FIX | |
d696c285 | 1073 | i += 3; |
c2646906 A |
1074 | } |
1075 | else if ( strcmp(arg, "-pagezero_size") == 0 ) { | |
1076 | fZeroPageSize = parseAddress(argv[++i]); | |
1077 | fZeroPageSize &= (-4096); // page align | |
1078 | } | |
1079 | else if ( strcmp(arg, "-stack_addr") == 0 ) { | |
1080 | fStackAddr = parseAddress(argv[++i]); | |
1081 | } | |
1082 | else if ( strcmp(arg, "-stack_size") == 0 ) { | |
1083 | fStackSize = parseAddress(argv[++i]); | |
1084 | } | |
d696c285 A |
1085 | else if ( strcmp(arg, "-allow_stack_execute") == 0 ) { |
1086 | fExecutableStack = true; | |
1087 | } | |
c2646906 A |
1088 | else if ( strcmp(arg, "-sectalign") == 0 ) { |
1089 | addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]); | |
1090 | i += 3; | |
1091 | } | |
1092 | else if ( strcmp(arg, "-sectorder_detail") == 0 ) { | |
1093 | // FIX FIX | |
1094 | } | |
1095 | else if ( strcmp(arg, "-sectobjectsymbols") == 0 ) { | |
1096 | // FIX FIX | |
1097 | i += 2; | |
1098 | } | |
1099 | else if ( strcmp(arg, "-bundle_loader") == 0 ) { | |
1100 | // FIX FIX | |
1101 | ++i; | |
1102 | } | |
1103 | else if ( strcmp(arg, "-private_bundle") == 0 ) { | |
1104 | // FIX FIX | |
1105 | } | |
1106 | else if ( strcmp(arg, "-twolevel_namespace_hints") == 0 ) { | |
1107 | // FIX FIX | |
1108 | } | |
d696c285 | 1109 | // Use this flag to set default behavior for deployement targets. |
c7f24d34 | 1110 | else if ( strcmp(arg, "-macosx_version_min") == 0 ) { |
d696c285 | 1111 | setVersionMin(argv[++i]); |
c7f24d34 | 1112 | } |
d696c285 A |
1113 | // This option (unlike -m below) only affects how we warn |
1114 | // on multiple definitions inside dynamic libraries. | |
c2646906 | 1115 | else if ( strcmp(arg, "-multiply_defined") == 0 ) { |
d696c285 A |
1116 | fMultiplyDefinedDynamic = parseTreatment(argv[++i]); |
1117 | ||
1118 | if ( fMultiplyDefinedDynamic == kNULL ) | |
1119 | throw "-multiply_defined missing [ warning | error | suppress ]"; | |
1120 | else if ( fMultiplyDefinedDynamic == kInvalid ) | |
1121 | throw "invalid option to -multiply_defined [ warning | error | suppress ]"; | |
c2646906 A |
1122 | } |
1123 | else if ( strcmp(arg, "-multiply_defined_unused") == 0 ) { | |
d696c285 A |
1124 | fMultiplyDefinedUnused = parseTreatment(argv[++i]); |
1125 | ||
1126 | if ( fMultiplyDefinedUnused == kNULL ) | |
1127 | throw "-multiply_defined_unused missing [ warning | error | suppress ]"; | |
1128 | else if ( fMultiplyDefinedUnused == kInvalid ) | |
1129 | throw "invalid option to -multiply_defined_unused [ warning | error | suppress ]"; | |
c2646906 A |
1130 | } |
1131 | else if ( strcmp(arg, "-nomultidefs") == 0 ) { | |
1132 | // FIX FIX | |
1133 | } | |
d696c285 A |
1134 | // Display each file in which the argument symbol appears and whether |
1135 | // the file defines or references it. This option takes an argument | |
1136 | // as -y<symbol> note that there is no space. | |
1137 | else if ( strncmp(arg, "-y", 2) == 0 ) { | |
1138 | const char* name = &arg[2]; | |
1139 | ||
1140 | if ( name == NULL ) | |
1141 | throw "-y missing argument"; | |
1142 | ||
1143 | fTraceSymbols.push_back(name); | |
c2646906 | 1144 | } |
d696c285 | 1145 | // Same output as -y, but output <arg> number of undefined symbols only. |
c2646906 | 1146 | else if ( strcmp(arg, "-Y") == 0 ) { |
d696c285 A |
1147 | char* endptr; |
1148 | fLimitUndefinedSymbols = strtoul (argv[++i], &endptr, 10); | |
1149 | ||
1150 | if(*endptr != '\0') | |
1151 | throw "invalid argument for -Y [decimal number]"; | |
c2646906 | 1152 | } |
d696c285 | 1153 | // This option affects all objects linked into the final result. |
c2646906 | 1154 | else if ( strcmp(arg, "-m") == 0 ) { |
d696c285 | 1155 | fWarnOnMultiplyDefined = true; |
c2646906 A |
1156 | } |
1157 | else if ( strcmp(arg, "-whyload") == 0 ) { | |
1158 | // FIX FIX | |
1159 | } | |
1160 | else if ( strcmp(arg, "-u") == 0 ) { | |
1161 | const char* name = argv[++i]; | |
1162 | if ( name == NULL ) | |
1163 | throw "-u missing argument"; | |
1164 | fInitialUndefines.push_back(name); | |
1165 | } | |
c2646906 A |
1166 | else if ( strcmp(arg, "-U") == 0 ) { |
1167 | // FIX FIX | |
d696c285 | 1168 | ++i; |
c2646906 A |
1169 | } |
1170 | else if ( strcmp(arg, "-s") == 0 ) { | |
d696c285 A |
1171 | fStripLocalSymbols = true; |
1172 | fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone; | |
c2646906 A |
1173 | } |
1174 | else if ( strcmp(arg, "-x") == 0 ) { | |
d696c285 | 1175 | fStripLocalSymbols = true; |
c2646906 A |
1176 | } |
1177 | else if ( strcmp(arg, "-S") == 0 ) { | |
d696c285 | 1178 | fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone; |
c2646906 A |
1179 | } |
1180 | else if ( strcmp(arg, "-X") == 0 ) { | |
1181 | // FIX FIX | |
1182 | } | |
1183 | else if ( strcmp(arg, "-Si") == 0 ) { | |
d696c285 | 1184 | fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoFull; |
c2646906 A |
1185 | } |
1186 | else if ( strcmp(arg, "-b") == 0 ) { | |
1187 | // FIX FIX | |
1188 | } | |
1189 | else if ( strcmp(arg, "-Sn") == 0 ) { | |
d696c285 A |
1190 | fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoFull; |
1191 | } | |
1192 | else if ( strcmp(arg, "-Sp") == 0 ) { | |
1193 | fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoMinimal; | |
c2646906 A |
1194 | } |
1195 | else if ( strcmp(arg, "-dead_strip") == 0 ) { | |
d696c285 A |
1196 | //fDeadStrip = kDeadStripOnPlusUnusedInits; |
1197 | fprintf(stderr, "ld64: warning -dead_strip not yet supported in ld64\n"); | |
1198 | } | |
1199 | else if ( strcmp(arg, "-no_dead_strip_inits_and_terms") == 0 ) { | |
1200 | //fDeadStrip = kDeadStripOn; | |
1201 | fprintf(stderr, "ld64: warning -dead_strip not yet supported in ld64\n"); | |
c2646906 | 1202 | } |
c2646906 A |
1203 | else if ( strcmp(arg, "-w") == 0 ) { |
1204 | // FIX FIX | |
1205 | } | |
1206 | else if ( strcmp(arg, "-arch_errors_fatal") == 0 ) { | |
1207 | // FIX FIX | |
1208 | } | |
1209 | else if ( strcmp(arg, "-M") == 0 ) { | |
1210 | // FIX FIX | |
1211 | } | |
1212 | else if ( strcmp(arg, "-whatsloaded") == 0 ) { | |
1213 | // FIX FIX | |
1214 | } | |
1215 | else if ( strcmp(arg, "-headerpad") == 0 ) { | |
1216 | const char* size = argv[++i]; | |
1217 | if ( size == NULL ) | |
1218 | throw "-headerpad missing argument"; | |
1219 | fMinimumHeaderPad = parseAddress(size); | |
1220 | } | |
1221 | else if ( strcmp(arg, "-headerpad_max_install_names") == 0 ) { | |
1222 | // FIX FIX | |
1223 | } | |
1224 | else if ( strcmp(arg, "-t") == 0 ) { | |
1225 | // FIX FIX | |
1226 | } | |
1227 | else if ( strcmp(arg, "-A") == 0 ) { | |
1228 | // FIX FIX | |
d696c285 | 1229 | ++i; |
c2646906 A |
1230 | } |
1231 | else if ( strcmp(arg, "-umbrella") == 0 ) { | |
1232 | const char* name = argv[++i]; | |
1233 | if ( name == NULL ) | |
1234 | throw "-umbrella missing argument"; | |
1235 | fUmbrellaName = name; | |
1236 | } | |
1237 | else if ( strcmp(arg, "-allowable_client") == 0 ) { | |
d696c285 A |
1238 | const char* name = argv[++i]; |
1239 | ||
1240 | if ( name == NULL ) | |
1241 | throw "-allowable_client missing argument"; | |
1242 | ||
1243 | fAllowableClients.push_back(name); | |
c2646906 A |
1244 | } |
1245 | else if ( strcmp(arg, "-client_name") == 0 ) { | |
d696c285 A |
1246 | const char* name = argv[++i]; |
1247 | ||
1248 | if ( name == NULL ) | |
1249 | throw "-client_name missing argument"; | |
1250 | ||
1251 | fClientName = name; | |
c2646906 A |
1252 | } |
1253 | else if ( strcmp(arg, "-sub_umbrella") == 0 ) { | |
1254 | const char* name = argv[++i]; | |
1255 | if ( name == NULL ) | |
1256 | throw "-sub_umbrella missing argument"; | |
1257 | fSubUmbellas.push_back(name); | |
1258 | } | |
1259 | else if ( strcmp(arg, "-sub_library") == 0 ) { | |
1260 | const char* name = argv[++i]; | |
1261 | if ( name == NULL ) | |
1262 | throw "-sub_library missing argument"; | |
1263 | fSubLibraries.push_back(name); | |
1264 | } | |
1265 | else if ( strcmp(arg, "-init") == 0 ) { | |
1266 | const char* name = argv[++i]; | |
1267 | if ( name == NULL ) | |
1268 | throw "-init missing argument"; | |
1269 | fInitFunctionName = name; | |
1270 | } | |
d696c285 A |
1271 | else if ( strcmp(arg, "-dot") == 0 ) { |
1272 | const char* name = argv[++i]; | |
1273 | if ( name == NULL ) | |
1274 | throw "-dot missing argument"; | |
1275 | fDotOutputFile = name; | |
1276 | } | |
c2646906 A |
1277 | else if ( strcmp(arg, "-warn_commons") == 0 ) { |
1278 | fWarnCommons = true; | |
1279 | } | |
1280 | else if ( strcmp(arg, "-commons") == 0 ) { | |
1281 | fCommonsMode = parseCommonsTreatment(argv[++i]); | |
1282 | } | |
d696c285 A |
1283 | else if ( strcmp(arg, "-keep_relocs") == 0 ) { |
1284 | fKeepRelocations = true; | |
1285 | } | |
1286 | else if ( strcmp(arg, "-warn_stabs") == 0 ) { | |
1287 | fWarnStabs = true; | |
1288 | } | |
1289 | else if ( strcmp(arg, "-pause") == 0 ) { | |
1290 | fPause = true; | |
1291 | } | |
1292 | else if ( strcmp(arg, "-print_statistics") == 0 ) { | |
1293 | fStatistics = true; | |
1294 | } | |
6e880c60 A |
1295 | else if ( strcmp(arg, "-v") == 0 ) { |
1296 | // previously handled by buildSearchPaths() | |
1297 | } | |
1298 | else if ( strcmp(arg, "-Z") == 0 ) { | |
1299 | // previously handled by buildSearchPaths() | |
1300 | } | |
1301 | else if ( strcmp(arg, "-syslibroot") == 0 ) { | |
1302 | ++i; | |
1303 | // previously handled by buildSearchPaths() | |
1304 | } | |
d696c285 A |
1305 | else if ( strcmp(arg, "-no_uuid") == 0 ) { |
1306 | fEmitUUID = false; | |
1307 | } | |
1308 | // put this last so that it does not interfer with other options starting with 'i' | |
1309 | else if ( strncmp(arg, "-i", 2) == 0 ) { | |
1310 | fprintf(stderr, "ld64: -i option (indirect symbols) not supported\n"); | |
1311 | } | |
c2646906 | 1312 | else { |
d696c285 | 1313 | throwf("unknown option: %s", arg); |
c2646906 A |
1314 | } |
1315 | } | |
1316 | else { | |
6e880c60 | 1317 | fInputFiles.push_back(findFile(arg)); |
c2646906 A |
1318 | } |
1319 | } | |
1320 | } | |
1321 | ||
d696c285 A |
1322 | // |
1323 | // -syslibroot <path> is used for SDK support. | |
6e880c60 A |
1324 | // The rule is that all search paths (both explicit and default) are |
1325 | // checked to see if they exist in the SDK. If so, that path is | |
1326 | // replaced with the sdk prefixed path. If not, that search path | |
1327 | // is used as is. If multiple -syslibroot options are specified | |
1328 | // their directory structures are logically overlayed and files | |
1329 | // from sdks specified earlier on the command line used before later ones. | |
d696c285 | 1330 | |
c2646906 A |
1331 | void Options::buildSearchPaths(int argc, const char* argv[]) |
1332 | { | |
1333 | bool addStandardLibraryDirectories = true; | |
6e880c60 A |
1334 | std::vector<const char*> libraryPaths; |
1335 | std::vector<const char*> frameworkPaths; | |
d696c285 A |
1336 | libraryPaths.reserve(10); |
1337 | frameworkPaths.reserve(10); | |
6e880c60 | 1338 | // scan through argv looking for -L, -F, -Z, and -syslibroot options |
c2646906 A |
1339 | for(int i=0; i < argc; ++i) { |
1340 | if ( (argv[i][0] == '-') && (argv[i][1] == 'L') ) | |
6e880c60 | 1341 | libraryPaths.push_back(&argv[i][2]); |
c2646906 | 1342 | else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') ) |
6e880c60 | 1343 | frameworkPaths.push_back(&argv[i][2]); |
c2646906 A |
1344 | else if ( strcmp(argv[i], "-Z") == 0 ) |
1345 | addStandardLibraryDirectories = false; | |
6e880c60 A |
1346 | else if ( strcmp(argv[i], "-v") == 0 ) { |
1347 | fVerbose = true; | |
1348 | extern const char ld64VersionString[]; | |
1349 | fprintf(stderr, "%s", ld64VersionString); | |
1350 | // if only -v specified, exit cleanly | |
1351 | if ( argc == 2 ) | |
1352 | exit(0); | |
1353 | } | |
1354 | else if ( strcmp(argv[i], "-syslibroot") == 0 ) { | |
1355 | const char* path = argv[++i]; | |
1356 | if ( path == NULL ) | |
1357 | throw "-syslibroot missing argument"; | |
1358 | fSDKPaths.push_back(path); | |
1359 | } | |
c2646906 A |
1360 | } |
1361 | if ( addStandardLibraryDirectories ) { | |
6e880c60 A |
1362 | libraryPaths.push_back("/usr/lib"); |
1363 | libraryPaths.push_back("/usr/local/lib"); | |
d696c285 | 1364 | |
6e880c60 A |
1365 | frameworkPaths.push_back("/Library/Frameworks/"); |
1366 | frameworkPaths.push_back("/Network/Library/Frameworks/"); | |
1367 | frameworkPaths.push_back("/System/Library/Frameworks/"); | |
1368 | } | |
d696c285 | 1369 | |
6e880c60 | 1370 | // now merge sdk and library paths to make real search paths |
d696c285 | 1371 | fLibrarySearchPaths.reserve(libraryPaths.size()*(fSDKPaths.size()+1)); |
6e880c60 A |
1372 | for (std::vector<const char*>::iterator it = libraryPaths.begin(); it != libraryPaths.end(); it++) { |
1373 | const char* libDir = *it; | |
1374 | bool sdkOverride = false; | |
1375 | if ( libDir[0] == '/' ) { | |
1376 | char betterLibDir[PATH_MAX]; | |
1377 | if ( strstr(libDir, "/..") != NULL ) { | |
1378 | if ( realpath(libDir, betterLibDir) != NULL ) | |
d696c285 | 1379 | libDir = strdup(betterLibDir); |
6e880c60 A |
1380 | } |
1381 | const int libDirLen = strlen(libDir); | |
1382 | for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) { | |
d696c285 | 1383 | // ??? Should be using string here. |
6e880c60 A |
1384 | const char* sdkDir = *sdkit; |
1385 | const int sdkDirLen = strlen(sdkDir); | |
1386 | char newPath[libDirLen + sdkDirLen+4]; | |
1387 | strcpy(newPath, sdkDir); | |
1388 | if ( newPath[sdkDirLen-1] == '/' ) | |
1389 | newPath[sdkDirLen-1] = '\0'; | |
1390 | strcat(newPath, libDir); | |
1391 | struct stat statBuffer; | |
1392 | if ( stat(newPath, &statBuffer) == 0 ) { | |
1393 | fLibrarySearchPaths.push_back(strdup(newPath)); | |
1394 | sdkOverride = true; | |
1395 | } | |
1396 | } | |
1397 | } | |
d696c285 | 1398 | if ( !sdkOverride ) |
6e880c60 A |
1399 | fLibrarySearchPaths.push_back(libDir); |
1400 | } | |
d696c285 | 1401 | |
6e880c60 | 1402 | // now merge sdk and framework paths to make real search paths |
d696c285 | 1403 | fFrameworkSearchPaths.reserve(frameworkPaths.size()*(fSDKPaths.size()+1)); |
6e880c60 A |
1404 | for (std::vector<const char*>::iterator it = frameworkPaths.begin(); it != frameworkPaths.end(); it++) { |
1405 | const char* frameworkDir = *it; | |
1406 | bool sdkOverride = false; | |
1407 | if ( frameworkDir[0] == '/' ) { | |
1408 | char betterFrameworkDir[PATH_MAX]; | |
1409 | if ( strstr(frameworkDir, "/..") != NULL ) { | |
1410 | if ( realpath(frameworkDir, betterFrameworkDir) != NULL ) | |
d696c285 | 1411 | frameworkDir = strdup(betterFrameworkDir); |
6e880c60 A |
1412 | } |
1413 | const int frameworkDirLen = strlen(frameworkDir); | |
1414 | for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) { | |
d696c285 | 1415 | // ??? Should be using string here |
6e880c60 A |
1416 | const char* sdkDir = *sdkit; |
1417 | const int sdkDirLen = strlen(sdkDir); | |
1418 | char newPath[frameworkDirLen + sdkDirLen+4]; | |
1419 | strcpy(newPath, sdkDir); | |
1420 | if ( newPath[sdkDirLen-1] == '/' ) | |
1421 | newPath[sdkDirLen-1] = '\0'; | |
1422 | strcat(newPath, frameworkDir); | |
1423 | struct stat statBuffer; | |
1424 | if ( stat(newPath, &statBuffer) == 0 ) { | |
1425 | fFrameworkSearchPaths.push_back(strdup(newPath)); | |
1426 | sdkOverride = true; | |
1427 | } | |
1428 | } | |
1429 | } | |
d696c285 | 1430 | if ( !sdkOverride ) |
6e880c60 A |
1431 | fFrameworkSearchPaths.push_back(frameworkDir); |
1432 | } | |
d696c285 | 1433 | |
6e880c60 A |
1434 | if ( fVerbose ) { |
1435 | fprintf(stderr,"Library search paths:\n"); | |
d696c285 A |
1436 | for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); |
1437 | it != fLibrarySearchPaths.end(); | |
1438 | it++) | |
6e880c60 A |
1439 | fprintf(stderr,"\t%s\n", *it); |
1440 | fprintf(stderr,"Framework search paths:\n"); | |
d696c285 A |
1441 | for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); |
1442 | it != fFrameworkSearchPaths.end(); | |
1443 | it++) | |
6e880c60 | 1444 | fprintf(stderr,"\t%s\n", *it); |
c2646906 A |
1445 | } |
1446 | } | |
1447 | ||
1448 | // this is run before the command line is parsed | |
1449 | void Options::parsePreCommandLineEnvironmentSettings() | |
1450 | { | |
d696c285 A |
1451 | if ((getenv("LD_TRACE_ARCHIVES") != NULL) |
1452 | || (getenv("RC_TRACE_ARCHIVES") != NULL)) | |
c2646906 | 1453 | fReaderOptions.fTraceArchives = true; |
d696c285 A |
1454 | |
1455 | if ((getenv("LD_TRACE_DYLIBS") != NULL) | |
1456 | || (getenv("RC_TRACE_DYLIBS") != NULL)) { | |
c2646906 A |
1457 | fReaderOptions.fTraceDylibs = true; |
1458 | fReaderOptions.fTraceIndirectDylibs = true; | |
1459 | } | |
d696c285 A |
1460 | |
1461 | if (getenv("RC_TRACE_DYLIB_SEARCHING") != NULL) { | |
1462 | fTraceDylibSearching = true; | |
1463 | } | |
1464 | ||
1465 | if (getenv("LD_PRINT_OPTIONS") != NULL) | |
1466 | fPrintOptions = true; | |
1467 | ||
1468 | if (fReaderOptions.fTraceDylibs || fReaderOptions.fTraceArchives) | |
1469 | fReaderOptions.fTraceOutputFile = getenv("LD_TRACE_FILE"); | |
c2646906 A |
1470 | } |
1471 | ||
1472 | // this is run after the command line is parsed | |
1473 | void Options::parsePostCommandLineEnvironmentSettings() | |
1474 | { | |
d696c285 A |
1475 | // when building a dynamic main executable, default any use of @executable_path to output path |
1476 | if ( fExecutablePath == NULL && (fOutputKind == kDynamicExecutable) ) { | |
1477 | fExecutablePath = fOutputFile; | |
1478 | } | |
c2646906 A |
1479 | } |
1480 | ||
1481 | void Options::checkIllegalOptionCombinations() | |
1482 | { | |
1483 | // check -undefined setting | |
1484 | switch ( fUndefinedTreatment ) { | |
1485 | case kUndefinedError: | |
1486 | case kUndefinedDynamicLookup: | |
1487 | // always legal | |
1488 | break; | |
1489 | case kUndefinedWarning: | |
1490 | case kUndefinedSuppress: | |
1491 | // requires flat namespace | |
1492 | if ( fNameSpace == kTwoLevelNameSpace ) | |
1493 | throw "can't use -undefined warning or suppress with -twolevel_namespace"; | |
1494 | break; | |
1495 | } | |
d696c285 | 1496 | |
c2646906 A |
1497 | // unify -sub_umbrella with dylibs |
1498 | for (std::vector<const char*>::iterator it = fSubUmbellas.begin(); it != fSubUmbellas.end(); it++) { | |
1499 | const char* subUmbrella = *it; | |
1500 | bool found = false; | |
1501 | for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) { | |
1502 | Options::FileInfo& info = *fit; | |
1503 | const char* lastSlash = strrchr(info.path, '/'); | |
1504 | if ( lastSlash == NULL ) | |
1505 | lastSlash = info.path - 1; | |
1506 | if ( strcmp(&lastSlash[1], subUmbrella) == 0 ) { | |
1507 | info.options.fReExport = true; | |
1508 | found = true; | |
1509 | break; | |
1510 | } | |
1511 | } | |
1512 | if ( ! found ) | |
1513 | fprintf(stderr, "ld64 warning: -sub_umbrella %s does not match a supplied dylib\n", subUmbrella); | |
1514 | } | |
d696c285 | 1515 | |
c2646906 A |
1516 | // unify -sub_library with dylibs |
1517 | for (std::vector<const char*>::iterator it = fSubLibraries.begin(); it != fSubLibraries.end(); it++) { | |
1518 | const char* subLibrary = *it; | |
1519 | bool found = false; | |
1520 | for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) { | |
1521 | Options::FileInfo& info = *fit; | |
1522 | const char* lastSlash = strrchr(info.path, '/'); | |
1523 | if ( lastSlash == NULL ) | |
1524 | lastSlash = info.path - 1; | |
1525 | const char* dot = strchr(lastSlash, '.'); | |
1526 | if ( dot == NULL ) | |
1527 | dot = &lastSlash[strlen(lastSlash)]; | |
1528 | if ( strncmp(&lastSlash[1], subLibrary, dot-lastSlash-1) == 0 ) { | |
1529 | info.options.fReExport = true; | |
1530 | found = true; | |
1531 | break; | |
1532 | } | |
1533 | } | |
1534 | if ( ! found ) | |
1535 | fprintf(stderr, "ld64 warning: -sub_library %s does not match a supplied dylib\n", subLibrary); | |
1536 | } | |
d696c285 | 1537 | |
c2646906 A |
1538 | // sync reader options |
1539 | if ( fNameSpace != kTwoLevelNameSpace ) | |
1540 | fReaderOptions.fFlatNamespace = true; | |
1541 | ||
1542 | // check -stack_addr | |
d696c285 | 1543 | if ( fStackAddr != 0 ) { |
c2646906 A |
1544 | switch (fArchitecture) { |
1545 | case CPU_TYPE_I386: | |
1546 | case CPU_TYPE_POWERPC: | |
d696c285 | 1547 | if ( fStackAddr > 0xFFFFFFFF ) |
c2646906 A |
1548 | throw "-stack_addr must be < 4G for 32-bit processes"; |
1549 | break; | |
1550 | case CPU_TYPE_POWERPC64: | |
1551 | break; | |
1552 | } | |
1553 | if ( (fStackAddr & -4096) != fStackAddr ) | |
1554 | throw "-stack_addr must be multiples of 4K"; | |
1555 | if ( fStackSize == 0 ) | |
1556 | throw "-stack_addr must be used with -stack_size"; | |
1557 | } | |
d696c285 | 1558 | |
c2646906 | 1559 | // check -stack_size |
d696c285 | 1560 | if ( fStackSize != 0 ) { |
c2646906 A |
1561 | switch (fArchitecture) { |
1562 | case CPU_TYPE_I386: | |
1563 | case CPU_TYPE_POWERPC: | |
d696c285 | 1564 | if ( fStackSize > 0xFFFFFFFF ) |
c2646906 A |
1565 | throw "-stack_size must be < 4G for 32-bit processes"; |
1566 | if ( fStackAddr == 0 ) { | |
1567 | fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0xC0000000\n"); | |
1568 | fStackAddr = 0xC0000000; | |
1569 | } | |
1570 | break; | |
1571 | case CPU_TYPE_POWERPC64: | |
1572 | if ( fStackAddr == 0 ) { | |
1573 | fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0x0008000000000000\n"); | |
1574 | fStackAddr = 0x0008000000000000LL; | |
1575 | } | |
1576 | break; | |
1577 | } | |
1578 | if ( (fStackSize & -4096) != fStackSize ) | |
1579 | throw "-stack_size must be multiples of 4K"; | |
1580 | switch ( fOutputKind ) { | |
1581 | case Options::kDynamicExecutable: | |
1582 | case Options::kStaticExecutable: | |
d696c285 | 1583 | // custom stack size only legal when building main executable |
c2646906 A |
1584 | break; |
1585 | case Options::kDynamicLibrary: | |
1586 | case Options::kDynamicBundle: | |
1587 | case Options::kObjectFile: | |
1588 | case Options::kDyld: | |
1589 | throw "-stack_size option can only be used when linking a main executable"; | |
1590 | } | |
1591 | } | |
d696c285 A |
1592 | |
1593 | // check that -allow_stack_execute is only used with main executables | |
1594 | if ( fExecutableStack ) { | |
1595 | switch ( fOutputKind ) { | |
1596 | case Options::kDynamicExecutable: | |
1597 | case Options::kStaticExecutable: | |
1598 | // -allow_stack_execute size only legal when building main executable | |
1599 | break; | |
1600 | case Options::kDynamicLibrary: | |
1601 | case Options::kDynamicBundle: | |
1602 | case Options::kObjectFile: | |
1603 | case Options::kDyld: | |
1604 | throw "-allow_stack_execute option can only be used when linking a main executable"; | |
1605 | } | |
1606 | } | |
1607 | ||
1608 | // check -client_name is only used when -bundle is specified | |
1609 | if ( (fClientName != NULL) && (fOutputKind != Options::kDynamicBundle) ) | |
1610 | throw "-client_name can only be used with -bundle"; | |
1611 | ||
c2646906 A |
1612 | // check -init is only used when building a dylib |
1613 | if ( (fInitFunctionName != NULL) && (fOutputKind != Options::kDynamicLibrary) ) | |
1614 | throw "-init can only be used with -dynamiclib"; | |
c2646906 | 1615 | |
d696c285 A |
1616 | // make sure all required exported symbols exist |
1617 | for (NameSet::iterator it=fExportSymbols.begin(); it != fExportSymbols.end(); it++) { | |
1618 | const char* name = *it; | |
1619 | // never export .eh symbols | |
1620 | if ( strcmp(&name[strlen(name)-3], ".eh") != 0 ) | |
1621 | fInitialUndefines.push_back(name); | |
1622 | } | |
c2646906 | 1623 | |
d696c285 | 1624 | } |