]>
Commit | Line | Data |
---|---|---|
c2646906 A |
1 | /* |
2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | #include <sys/types.h> | |
26 | #include <sys/stat.h> | |
27 | #include <fcntl.h> | |
28 | ||
29 | ||
30 | #include "Options.h" | |
31 | ||
32 | __attribute__((noreturn)) | |
33 | void throwf(const char* format, ...) | |
34 | { | |
35 | va_list list; | |
36 | char* p; | |
37 | va_start(list, format); | |
38 | vasprintf(&p, format, list); | |
39 | va_end(list); | |
40 | ||
41 | const char* t = p; | |
42 | throw t; | |
43 | } | |
44 | ||
45 | ||
46 | Options::Options(int argc, const char* argv[]) | |
47 | : fOutputFile("a.out"), fArchitecture(CPU_TYPE_POWERPC64), fOutputKind(kDynamicExecutable), fBindAtLoad(false), | |
48 | fStripLocalSymbols(false), fKeepPrivateExterns(false), | |
49 | fInterposable(false), fIgnoreOtherArchFiles(false), fForceSubtypeAll(false), fNameSpace(kTwoLevelNameSpace), | |
50 | fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fEntryName("start"), fBaseAddress(0), | |
51 | fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives), | |
52 | fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), fPICTreatment(kPICError), | |
53 | fWeakReferenceMismatchTreatment(kWeakReferenceMismatchError), | |
54 | fUmbrellaName(NULL), fInitFunctionName(NULL), fZeroPageSize(0x1000), fStackSize(0), fStackAddr(0), fMinimumHeaderPad(0), | |
55 | fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false) | |
56 | { | |
57 | this->parsePreCommandLineEnvironmentSettings(); | |
58 | this->parse(argc, argv); | |
59 | this->parsePostCommandLineEnvironmentSettings(); | |
60 | this->checkIllegalOptionCombinations(); | |
61 | } | |
62 | ||
63 | Options::~Options() | |
64 | { | |
65 | } | |
66 | ||
67 | ||
68 | ObjectFile::ReaderOptions& Options::readerOptions() | |
69 | { | |
70 | return fReaderOptions; | |
71 | } | |
72 | ||
73 | cpu_type_t Options::architecture() | |
74 | { | |
75 | return fArchitecture; | |
76 | } | |
77 | ||
78 | ||
79 | const char* Options::getOutputFilePath() | |
80 | { | |
81 | return fOutputFile; | |
82 | } | |
83 | ||
84 | ||
85 | std::vector<Options::FileInfo>& Options::getInputFiles() | |
86 | { | |
87 | return fInputFiles; | |
88 | } | |
89 | ||
90 | Options::OutputKind Options::outputKind() | |
91 | { | |
92 | return fOutputKind; | |
93 | } | |
94 | ||
95 | bool Options::stripLocalSymbols() | |
96 | { | |
97 | return fStripLocalSymbols; | |
98 | } | |
99 | ||
100 | bool Options::stripDebugInfo() | |
101 | { | |
102 | return fReaderOptions.fStripDebugInfo; | |
103 | } | |
104 | ||
105 | bool Options::bindAtLoad() | |
106 | { | |
107 | return fBindAtLoad; | |
108 | } | |
109 | ||
110 | bool Options::fullyLoadArchives() | |
111 | { | |
112 | return fReaderOptions.fFullyLoadArchives; | |
113 | } | |
114 | ||
115 | Options::NameSpace Options::nameSpace() | |
116 | { | |
117 | return fNameSpace; | |
118 | } | |
119 | ||
120 | const char* Options::installPath() | |
121 | { | |
122 | if ( fDylibInstallName != NULL ) | |
123 | return fDylibInstallName; | |
124 | else | |
125 | return fOutputFile; | |
126 | } | |
127 | ||
128 | uint32_t Options::currentVersion() | |
129 | { | |
130 | return fDylibCurrentVersion; | |
131 | } | |
132 | ||
133 | uint32_t Options::compatibilityVersion() | |
134 | { | |
135 | return fDylibCompatVersion; | |
136 | } | |
137 | ||
138 | const char* Options::entryName() | |
139 | { | |
140 | return fEntryName; | |
141 | } | |
142 | ||
143 | uint64_t Options::baseAddress() | |
144 | { | |
145 | return fBaseAddress; | |
146 | } | |
147 | ||
148 | bool Options::keepPrivateExterns() | |
149 | { | |
150 | return fKeepPrivateExterns; | |
151 | } | |
152 | ||
153 | bool Options::interposable() | |
154 | { | |
155 | return fInterposable; | |
156 | } | |
157 | ||
158 | bool Options::ignoreOtherArchInputFiles() | |
159 | { | |
160 | return fIgnoreOtherArchFiles; | |
161 | } | |
162 | ||
163 | bool Options::forceCpuSubtypeAll() | |
164 | { | |
165 | return fForceSubtypeAll; | |
166 | } | |
167 | ||
168 | bool Options::traceDylibs() | |
169 | { | |
170 | return fReaderOptions.fTraceDylibs; | |
171 | } | |
172 | ||
173 | bool Options::traceArchives() | |
174 | { | |
175 | return fReaderOptions.fTraceArchives; | |
176 | } | |
177 | ||
178 | Options::UndefinedTreatment Options::undefinedTreatment() | |
179 | { | |
180 | return fUndefinedTreatment; | |
181 | } | |
182 | ||
183 | Options::WeakReferenceMismatchTreatment Options::weakReferenceMismatchTreatment() | |
184 | { | |
185 | return fWeakReferenceMismatchTreatment; | |
186 | } | |
187 | ||
188 | const char* Options::umbrellaName() | |
189 | { | |
190 | return fUmbrellaName; | |
191 | } | |
192 | ||
193 | uint64_t Options::zeroPageSize() | |
194 | { | |
195 | return fZeroPageSize; | |
196 | } | |
197 | ||
198 | bool Options::hasCustomStack() | |
199 | { | |
200 | return (fStackSize != 0); | |
201 | } | |
202 | ||
203 | uint64_t Options::customStackSize() | |
204 | { | |
205 | return fStackSize; | |
206 | } | |
207 | ||
208 | uint64_t Options::customStackAddr() | |
209 | { | |
210 | return fStackAddr; | |
211 | } | |
212 | ||
213 | std::vector<const char*>& Options::initialUndefines() | |
214 | { | |
215 | return fInitialUndefines; | |
216 | } | |
217 | ||
218 | const char* Options::initFunctionName() | |
219 | { | |
220 | return fInitFunctionName; | |
221 | } | |
222 | ||
223 | bool Options::hasExportRestrictList() | |
224 | { | |
225 | return (fExportMode != kExportDefault); | |
226 | } | |
227 | ||
228 | uint32_t Options::minimumHeaderPad() | |
229 | { | |
230 | return fMinimumHeaderPad; | |
231 | } | |
232 | ||
233 | std::vector<Options::ExtraSection>& Options::extraSections() | |
234 | { | |
235 | return fExtraSections; | |
236 | } | |
237 | ||
238 | std::vector<Options::SectionAlignment>& Options::sectionAlignments() | |
239 | { | |
240 | return fSectionAlignments; | |
241 | } | |
242 | ||
243 | ||
244 | Options::CommonsMode Options::commonsMode() | |
245 | { | |
246 | return fCommonsMode; | |
247 | } | |
248 | ||
249 | bool Options::warnCommons() | |
250 | { | |
251 | return fWarnCommons; | |
252 | } | |
253 | ||
254 | ||
255 | bool Options::shouldExport(const char* symbolName) | |
256 | { | |
257 | switch (fExportMode) { | |
258 | case kExportSome: | |
259 | return ( fExportSymbols.find(symbolName) != fExportSymbols.end() ); | |
260 | case kDontExportSome: | |
261 | return ( fDontExportSymbols.find(symbolName) == fDontExportSymbols.end() ); | |
262 | case kExportDefault: | |
263 | return true; | |
264 | } | |
265 | throw "internal error"; | |
266 | } | |
267 | ||
268 | ||
269 | void Options::parseArch(const char* architecture) | |
270 | { | |
271 | if ( architecture == NULL ) | |
272 | throw "-arch must be followed by an architecture string"; | |
273 | if ( strcmp(architecture, "ppc") == 0 ) | |
274 | fArchitecture = CPU_TYPE_POWERPC; | |
275 | else if ( strcmp(architecture, "ppc64") == 0 ) | |
276 | fArchitecture = CPU_TYPE_POWERPC64; | |
277 | else if ( strcmp(architecture, "i386") == 0 ) | |
278 | fArchitecture = CPU_TYPE_I386; | |
279 | else | |
280 | throw "-arch followed by unknown architecture name"; | |
281 | } | |
282 | ||
283 | bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result) | |
284 | { | |
285 | struct stat statBuffer; | |
286 | char possiblePath[strlen(dir)+strlen(rootName)+20]; | |
287 | sprintf(possiblePath, format, dir, rootName); | |
288 | if ( stat(possiblePath, &statBuffer) == 0 ) { | |
289 | result.path = strdup(possiblePath); | |
290 | result.fileLen = statBuffer.st_size; | |
291 | return true; | |
292 | } | |
293 | return false; | |
294 | } | |
295 | ||
296 | ||
297 | Options::FileInfo Options::findLibrary(const char* rootName) | |
298 | { | |
299 | FileInfo result; | |
300 | const int rootNameLen = strlen(rootName); | |
301 | // if rootName ends in .o there is no .a vs .dylib choice | |
302 | if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) { | |
303 | for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) { | |
304 | const char* dir = *it; | |
305 | if ( checkForFile("%s/%s", dir, rootName, result) ) | |
306 | return result; | |
307 | } | |
308 | } | |
309 | else { | |
310 | bool lookForDylibs = ( fOutputKind != Options::kDyld); | |
311 | switch ( fLibrarySearchMode ) { | |
312 | case kSearchAllDirsForDylibsThenAllDirsForArchives: | |
313 | // first look in all directories for just for dylibs | |
314 | if ( lookForDylibs ) { | |
315 | for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) { | |
316 | const char* dir = *it; | |
317 | if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) ) | |
318 | return result; | |
319 | } | |
320 | } | |
321 | // next look in all directories for just for archives | |
322 | for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) { | |
323 | const char* dir = *it; | |
324 | if ( checkForFile("%s/lib%s.a", dir, rootName, result) ) | |
325 | return result; | |
326 | } | |
327 | break; | |
328 | ||
329 | case kSearchDylibAndArchiveInEachDir: | |
330 | // look in each directory for just for a dylib then for an archive | |
331 | for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) { | |
332 | const char* dir = *it; | |
333 | if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) ) | |
334 | return result; | |
335 | if ( checkForFile("%s/lib%s.a", dir, rootName, result) ) | |
336 | return result; | |
337 | } | |
338 | break; | |
339 | } | |
340 | } | |
341 | throwf("library not found for -l%s", rootName); | |
342 | } | |
343 | ||
344 | ||
345 | Options::FileInfo Options::findFramework(const char* rootName) | |
346 | { | |
347 | struct stat statBuffer; | |
348 | const int rootNameLen = strlen(rootName); | |
349 | for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++) { | |
350 | const char* dir = *it; | |
351 | char possiblePath[strlen(dir)+2*rootNameLen+20]; | |
352 | strcpy(possiblePath, dir); | |
353 | strcat(possiblePath, "/"); | |
354 | strcat(possiblePath, rootName); | |
355 | strcat(possiblePath, ".framework/"); | |
356 | strcat(possiblePath, rootName); | |
357 | if ( stat(possiblePath, &statBuffer) == 0 ) { | |
358 | FileInfo result; | |
359 | result.path = strdup(possiblePath); | |
360 | result.fileLen = statBuffer.st_size; | |
361 | return result; | |
362 | } | |
363 | } | |
364 | throwf("framework not found %s", rootName); | |
365 | } | |
366 | ||
367 | ||
368 | Options::FileInfo Options::makeFileInfo(const char* path) | |
369 | { | |
370 | struct stat statBuffer; | |
371 | if ( stat(path, &statBuffer) == 0 ) { | |
372 | FileInfo result; | |
373 | result.path = strdup(path); | |
374 | result.fileLen = statBuffer.st_size; | |
375 | return result; | |
376 | } | |
377 | else { | |
378 | throwf("file not found: %s", path); | |
379 | } | |
380 | } | |
381 | ||
382 | void Options::loadFileList(const char* fileOfPaths) | |
383 | { | |
384 | FILE* file = fopen(fileOfPaths, "r"); | |
385 | if ( file == NULL ) | |
386 | throwf("-filelist file not found: %s\n", fileOfPaths); | |
387 | ||
388 | char path[1024]; | |
389 | while ( fgets(path, 1024, file) != NULL ) { | |
390 | path[1023] = '\0'; | |
391 | char* eol = strchr(path, '\n'); | |
392 | if ( eol != NULL ) | |
393 | *eol = '\0'; | |
394 | ||
395 | fInputFiles.push_back(makeFileInfo(path)); | |
396 | } | |
397 | fclose(file); | |
398 | } | |
399 | ||
400 | ||
401 | void Options::loadExportFile(const char* fileOfExports, const char* option, NameSet& set) | |
402 | { | |
403 | // read in whole file | |
404 | int fd = ::open(fileOfExports, O_RDONLY, 0); | |
405 | if ( fd == -1 ) | |
406 | throwf("can't open %s file: %s", option, fileOfExports); | |
407 | struct stat stat_buf; | |
408 | ::fstat(fd, &stat_buf); | |
409 | char* p = (char*)malloc(stat_buf.st_size); | |
410 | if ( p == NULL ) | |
411 | throwf("can't process %s file: %s", option, fileOfExports); | |
412 | ||
413 | if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) | |
414 | throwf("can't read %s file: %s", option, fileOfExports); | |
415 | ||
416 | ::close(fd); | |
417 | ||
418 | // parse into symbols and add to hash_set | |
419 | char * const end = &p[stat_buf.st_size]; | |
420 | enum { lineStart, inSymbol, inComment } state = lineStart; | |
421 | char* symbolStart = NULL; | |
422 | for (char* s = p; s < end; ++s ) { | |
423 | switch ( state ) { | |
424 | case lineStart: | |
425 | if ( *s =='#' ) { | |
426 | state = inComment; | |
427 | } | |
428 | else if ( !isspace(*s) ) { | |
429 | state = inSymbol; | |
430 | symbolStart = s; | |
431 | } | |
432 | break; | |
433 | case inSymbol: | |
434 | if ( *s == '\n' ) { | |
435 | *s = '\0'; | |
436 | // removing any trailing spaces | |
437 | char* last = s-1; | |
438 | while ( isspace(*last) ) { | |
439 | *last = '\0'; | |
440 | --last; | |
441 | } | |
442 | set.insert(symbolStart); | |
443 | symbolStart = NULL; | |
444 | state = lineStart; | |
445 | } | |
446 | break; | |
447 | case inComment: | |
448 | if ( *s == '\n' ) | |
449 | state = lineStart; | |
450 | break; | |
451 | } | |
452 | } | |
453 | // Note: we do not free() the malloc buffer, because the strings are used by the export-set hash table | |
454 | } | |
455 | ||
456 | void Options::setUndefinedTreatment(const char* treatment) | |
457 | { | |
458 | if ( treatment == NULL ) | |
459 | throw "-undefined missing [ warning | error | suppress | dynamic_lookup ]"; | |
460 | ||
461 | if ( strcmp(treatment, "warning") == 0 ) | |
462 | fUndefinedTreatment = kUndefinedWarning; | |
463 | else if ( strcmp(treatment, "error") == 0 ) | |
464 | fUndefinedTreatment = kUndefinedError; | |
465 | else if ( strcmp(treatment, "suppress") == 0 ) | |
466 | fUndefinedTreatment = kUndefinedSuppress; | |
467 | else if ( strcmp(treatment, "dynamic_lookup") == 0 ) | |
468 | fUndefinedTreatment = kUndefinedDynamicLookup; | |
469 | else | |
470 | throw "invalid option to -undefined [ warning | error | suppress | dynamic_lookup ]"; | |
471 | } | |
472 | ||
473 | void Options::setReadOnlyRelocTreatment(const char* treatment) | |
474 | { | |
475 | if ( treatment == NULL ) | |
476 | throw "-read_only_relocs missing [ warning | error | suppress ]"; | |
477 | ||
478 | if ( strcmp(treatment, "warning") == 0 ) | |
479 | throw "-read_only_relocs warning not supported"; | |
480 | else if ( strcmp(treatment, "suppress") == 0 ) | |
481 | throw "-read_only_relocs suppress not supported"; | |
482 | else if ( strcmp(treatment, "error") != 0 ) | |
483 | throw "invalid option to -read_only_relocs [ warning | error | suppress | dynamic_lookup ]"; | |
484 | } | |
485 | ||
486 | void Options::setPICTreatment(const char* treatment) | |
487 | { | |
488 | if ( treatment == NULL ) | |
489 | throw "-sect_diff_relocs missing [ warning | error | suppress ]"; | |
490 | ||
491 | if ( strcmp(treatment, "warning") == 0 ) | |
492 | fPICTreatment = kPICWarning; | |
493 | else if ( strcmp(treatment, "error") == 0 ) | |
494 | fPICTreatment = kPICError; | |
495 | else if ( strcmp(treatment, "suppress") == 0 ) | |
496 | fPICTreatment = kPICSuppress; | |
497 | else | |
498 | throw "invalid option to -sect_diff_relocs [ warning | error | suppress ]"; | |
499 | } | |
500 | ||
501 | void Options::setWeakReferenceMismatchTreatment(const char* treatment) | |
502 | { | |
503 | if ( treatment == NULL ) | |
504 | throw "-weak_reference_mismatches missing [ error | weak | non-weak ]"; | |
505 | ||
506 | if ( strcmp(treatment, "error") == 0 ) | |
507 | fWeakReferenceMismatchTreatment = kWeakReferenceMismatchError; | |
508 | else if ( strcmp(treatment, "weak") == 0 ) | |
509 | fWeakReferenceMismatchTreatment = kWeakReferenceMismatchWeak; | |
510 | else if ( strcmp(treatment, "non-weak") == 0 ) | |
511 | fWeakReferenceMismatchTreatment = kWeakReferenceMismatchNonWeak; | |
512 | else | |
513 | throw "invalid option to -weak_reference_mismatches [ error | weak | non-weak ]"; | |
514 | } | |
515 | ||
516 | Options::CommonsMode Options::parseCommonsTreatment(const char* mode) | |
517 | { | |
518 | if ( mode == NULL ) | |
519 | throw "-commons missing [ ignore_dylibs | use_dylibs | error ]"; | |
520 | ||
521 | if ( strcmp(mode, "ignore_dylibs") == 0 ) | |
522 | return kCommonsIgnoreDylibs; | |
523 | else if ( strcmp(mode, "use_dylibs") == 0 ) | |
524 | return kCommonsOverriddenByDylibs; | |
525 | else if ( strcmp(mode, "error") == 0 ) | |
526 | return kCommonsConflictsDylibsError; | |
527 | else | |
528 | throw "invalid option to -commons [ ignore_dylibs | use_dylibs | error ]"; | |
529 | } | |
530 | ||
531 | ||
532 | void Options::setDylibInstallNameOverride(const char* paths) | |
533 | { | |
534 | ||
535 | ||
536 | } | |
537 | ||
538 | void Options::setExecutablePath(const char* path) | |
539 | { | |
540 | ||
541 | ||
542 | } | |
543 | ||
544 | ||
545 | ||
546 | ||
547 | uint64_t Options::parseAddress(const char* addr) | |
548 | { | |
549 | char* endptr; | |
550 | uint64_t result = strtoull(addr, &endptr, 16); | |
551 | return result; | |
552 | } | |
553 | ||
554 | ||
555 | ||
556 | // | |
557 | // Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz | |
558 | // | |
559 | // | |
560 | uint32_t Options::parseVersionNumber(const char* versionString) | |
561 | { | |
562 | unsigned long x = 0; | |
563 | unsigned long y = 0; | |
564 | unsigned long z = 0; | |
565 | char* end; | |
566 | x = strtoul(versionString, &end, 10); | |
567 | if ( *end == '.' ) { | |
568 | y = strtoul(&end[1], &end, 10); | |
569 | if ( *end == '.' ) { | |
570 | z = strtoul(&end[1], &end, 10); | |
571 | } | |
572 | } | |
573 | if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) ) | |
574 | throwf("malformed version number: %s", versionString); | |
575 | ||
576 | return (x << 16) | ( y << 8 ) | z; | |
577 | } | |
578 | ||
579 | void Options::parseSectionOrderFile(const char* segment, const char* section, const char* path) | |
580 | { | |
581 | fprintf(stderr, "ld64: warning -sectorder not yet supported for 64-bit code\n"); | |
582 | } | |
583 | ||
584 | void Options::addSection(const char* segment, const char* section, const char* path) | |
585 | { | |
586 | if ( strlen(segment) > 16 ) | |
587 | throw "-seccreate segment name max 16 chars"; | |
588 | if ( strlen(section) > 16 ) | |
589 | throw "-seccreate section name max 16 chars"; | |
590 | ||
591 | // read in whole file | |
592 | int fd = ::open(path, O_RDONLY, 0); | |
593 | if ( fd == -1 ) | |
594 | throwf("can't open -sectcreate file: %s", path); | |
595 | struct stat stat_buf; | |
596 | ::fstat(fd, &stat_buf); | |
597 | char* p = (char*)malloc(stat_buf.st_size); | |
598 | if ( p == NULL ) | |
599 | throwf("can't process -sectcreate file: %s", path); | |
600 | if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) | |
601 | throwf("can't read -sectcreate file: %s", path); | |
602 | ::close(fd); | |
603 | ||
604 | // record section to create | |
605 | ExtraSection info = { segment, section, path, (uint8_t*)p, stat_buf.st_size }; | |
606 | fExtraSections.push_back(info); | |
607 | } | |
608 | ||
609 | void Options::addSectionAlignment(const char* segment, const char* section, const char* alignmentStr) | |
610 | { | |
611 | if ( strlen(segment) > 16 ) | |
612 | throw "-sectalign segment name max 16 chars"; | |
613 | if ( strlen(section) > 16 ) | |
614 | throw "-sectalign section name max 16 chars"; | |
615 | ||
616 | char* endptr; | |
617 | unsigned long value = strtoul(alignmentStr, &endptr, 16); | |
618 | if ( *endptr != '\0') | |
619 | throw "argument for -sectalign is not a hexadecimal number"; | |
620 | if ( value > 0x8000 ) | |
621 | throw "argument for -sectalign must be less than or equal to 0x8000"; | |
622 | uint8_t alignment = 0; | |
623 | for(unsigned long x=value; x != 1; x >>= 1) | |
624 | ++alignment; | |
625 | if ( (unsigned long)(1 << alignment) != value ) | |
626 | throw "argument for -sectalign is not a power of two"; | |
627 | ||
628 | SectionAlignment info = { segment, section, alignment }; | |
629 | fSectionAlignments.push_back(info); | |
630 | } | |
631 | ||
632 | ||
633 | void Options::parse(int argc, const char* argv[]) | |
634 | { | |
635 | // pass one builds search list from -L and -F options | |
636 | this->buildSearchPaths(argc, argv); | |
637 | ||
638 | // pass two parse all other options | |
639 | for(int i=1; i < argc; ++i) { | |
640 | const char* arg = argv[i]; | |
641 | ||
642 | if ( arg[0] == '-' ) { | |
643 | if ( (arg[1] == 'L') || (arg[1] == 'F') ) { | |
644 | // previously handled | |
645 | } | |
646 | else if ( strcmp(arg, "-arch") == 0 ) { | |
647 | parseArch(argv[++i]); | |
648 | } | |
649 | else if ( strcmp(arg, "-dynamic") == 0 ) { | |
650 | // default | |
651 | } | |
652 | else if ( strcmp(arg, "-static") == 0 ) { | |
653 | fOutputKind = kStaticExecutable; | |
654 | } | |
655 | else if ( strcmp(arg, "-dylib") == 0 ) { | |
656 | fOutputKind = kDynamicLibrary; | |
657 | } | |
658 | else if ( strcmp(arg, "-bundle") == 0 ) { | |
659 | fOutputKind = kDynamicBundle; | |
660 | } | |
661 | else if ( strcmp(arg, "-dylinker") == 0 ) { | |
662 | fOutputKind = kDyld; | |
663 | } | |
664 | else if ( strcmp(arg, "-execute") == 0 ) { | |
665 | if ( fOutputKind != kStaticExecutable ) | |
666 | fOutputKind = kDynamicExecutable; | |
667 | } | |
668 | else if ( strcmp(arg, "-r") == 0 ) { | |
669 | fOutputKind = kObjectFile; | |
670 | } | |
671 | else if ( strcmp(arg, "-o") == 0 ) { | |
672 | fOutputFile = argv[++i]; | |
673 | } | |
674 | else if ( arg[1] == 'l' ) { | |
675 | fInputFiles.push_back(findLibrary(&arg[2])); | |
676 | } | |
677 | else if ( strcmp(arg, "-weak-l") == 0 ) { | |
678 | FileInfo info = findLibrary(&arg[2]); | |
679 | info.options.fWeakImport = true; | |
680 | fInputFiles.push_back(info); | |
681 | } | |
682 | else if ( strcmp(arg, "-bind_at_load") == 0 ) { | |
683 | fBindAtLoad = true; | |
684 | } | |
685 | else if ( strcmp(arg, "-twolevel_namespace") == 0 ) { | |
686 | fNameSpace = kTwoLevelNameSpace; | |
687 | } | |
688 | else if ( strcmp(arg, "-flat_namespace") == 0 ) { | |
689 | fNameSpace = kFlatNameSpace; | |
690 | } | |
691 | else if ( strcmp(arg, "-force_flat_namespace") == 0 ) { | |
692 | fNameSpace = kForceFlatNameSpace; | |
693 | } | |
694 | else if ( strcmp(arg, "-all_load") == 0 ) { | |
695 | fReaderOptions.fFullyLoadArchives = true; | |
696 | } | |
697 | else if ( strcmp(arg, "-ObjC") == 0 ) { | |
698 | fReaderOptions.fLoadObjcClassesInArchives = true; | |
699 | } | |
700 | else if ( strcmp(arg, "-dylib_compatibility_version") == 0 ) { | |
701 | fDylibCompatVersion = parseVersionNumber(argv[++i]); | |
702 | } | |
703 | else if ( strcmp(arg, "-dylib_current_version") == 0 ) { | |
704 | fDylibCurrentVersion = parseVersionNumber(argv[++i]); | |
705 | } | |
706 | else if ( strcmp(arg, "-sectorder") == 0 ) { | |
707 | parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]); | |
708 | i += 3; | |
709 | } | |
710 | else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) { | |
711 | addSection(argv[i+1], argv[i+2], argv[i+3]); | |
712 | i += 3; | |
713 | } | |
714 | else if ( (strcmp(arg, "-dylib_install_name") == 0) || (strcmp(arg, "-dylinker_install_name") == 0) ) { | |
715 | fDylibInstallName = argv[++i]; | |
716 | } | |
717 | else if ( strcmp(arg, "-seg1addr") == 0 ) { | |
718 | fBaseAddress = parseAddress(argv[++i]); | |
719 | } | |
720 | else if ( strcmp(arg, "-e") == 0 ) { | |
721 | fEntryName = argv[++i]; | |
722 | } | |
723 | else if ( strcmp(arg, "-filelist") == 0 ) { | |
724 | loadFileList(argv[++i]); | |
725 | } | |
726 | else if ( strcmp(arg, "-keep_private_externs") == 0 ) { | |
727 | fKeepPrivateExterns = true; | |
728 | } | |
729 | else if ( strcmp(arg, "-final_output") == 0 ) { | |
730 | ++i; | |
731 | // ignore for now | |
732 | } | |
733 | else if ( (strcmp(arg, "-interposable") == 0) || (strcmp(arg, "-multi_module") == 0)) { | |
734 | fInterposable = true; | |
735 | } | |
736 | else if ( strcmp(arg, "-single_module") == 0 ) { | |
737 | fInterposable = false; | |
738 | } | |
739 | else if ( strcmp(arg, "-exported_symbols_list") == 0 ) { | |
740 | if ( fExportMode == kDontExportSome ) | |
741 | throw "can't use -exported_symbols_list and -unexported_symbols_list"; | |
742 | fExportMode = kExportSome; | |
743 | loadExportFile(argv[++i], "-exported_symbols_list", fExportSymbols); | |
744 | } | |
745 | else if ( strcmp(arg, "-unexported_symbols_list") == 0 ) { | |
746 | if ( fExportMode == kExportSome ) | |
747 | throw "can't use -exported_symbols_list and -unexported_symbols_list"; | |
748 | fExportMode = kDontExportSome; | |
749 | loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols); | |
750 | } | |
751 | else if ( strcmp(arg, "-no_arch_warnings") == 0 ) { | |
752 | fIgnoreOtherArchFiles = true; | |
753 | } | |
754 | else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) { | |
755 | fForceSubtypeAll = true; | |
756 | } | |
757 | else if ( strcmp(arg, "-weak_library") == 0 ) { | |
758 | FileInfo info = makeFileInfo(argv[++i]); | |
759 | info.options.fWeakImport = true; | |
760 | fInputFiles.push_back(info); | |
761 | } | |
762 | else if ( strcmp(arg, "-framework") == 0 ) { | |
763 | fInputFiles.push_back(findFramework(argv[++i])); | |
764 | } | |
765 | else if ( strcmp(arg, "-weak_framework") == 0 ) { | |
766 | FileInfo info = findFramework(argv[++i]); | |
767 | info.options.fWeakImport = true; | |
768 | fInputFiles.push_back(info); | |
769 | } | |
770 | else if ( strcmp(arg, "-search_paths_first") == 0 ) { | |
771 | fLibrarySearchMode = kSearchDylibAndArchiveInEachDir; | |
772 | } | |
773 | else if ( strcmp(arg, "-undefined") == 0 ) { | |
774 | setUndefinedTreatment(argv[++i]); | |
775 | } | |
776 | else if ( strcmp(arg, "-arch_multiple") == 0 ) { | |
777 | fMessagesPrefixedWithArchitecture = true; | |
778 | } | |
779 | else if ( strcmp(arg, "-read_only_relocs") == 0 ) { | |
780 | setReadOnlyRelocTreatment(argv[++i]); | |
781 | } | |
782 | else if ( strcmp(arg, "-sect_diff_relocs") == 0 ) { | |
783 | setPICTreatment(argv[++i]); | |
784 | } | |
785 | else if ( strcmp(arg, "-weak_reference_mismatches") == 0 ) { | |
786 | setWeakReferenceMismatchTreatment(argv[++i]); | |
787 | } | |
788 | else if ( strcmp(arg, "-prebind") == 0 ) { | |
789 | // FIX FIX | |
790 | } | |
791 | else if ( strcmp(arg, "-noprebind") == 0 ) { | |
792 | // FIX FIX | |
793 | } | |
794 | else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) { | |
795 | // FIX FIX | |
796 | } | |
797 | else if ( strcmp(arg, "-prebind_all_twolevel_modules") == 0 ) { | |
798 | // FIX FIX | |
799 | } | |
800 | else if ( strcmp(arg, "-noprebind_all_twolevel_modules") == 0 ) { | |
801 | // FIX FIX | |
802 | } | |
803 | else if ( strcmp(arg, "-nofixprebinding") == 0 ) { | |
804 | // FIX FIX | |
805 | } | |
806 | else if ( strcmp(arg, "-dylib_file") == 0 ) { | |
807 | setDylibInstallNameOverride(argv[++i]); | |
808 | } | |
809 | else if ( strcmp(arg, "-executable_path") == 0 ) { | |
810 | setExecutablePath(argv[++i]); | |
811 | } | |
812 | else if ( strcmp(arg, "-segalign") == 0 ) { | |
813 | // FIX FIX | |
814 | ++i; | |
815 | } | |
816 | else if ( strcmp(arg, "-segaddr") == 0 ) { | |
817 | // FIX FIX | |
818 | i += 2; | |
819 | } | |
820 | else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) { | |
821 | // FIX FIX | |
822 | ++i; | |
823 | } | |
824 | else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) { | |
825 | // FIX FIX | |
826 | ++i; | |
827 | } | |
828 | else if ( strcmp(arg, "-seg_addr_table") == 0 ) { | |
829 | // FIX FIX | |
830 | ++i; | |
831 | } | |
832 | else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) { | |
833 | // FIX FIX | |
834 | ++i; | |
835 | } | |
836 | else if ( strcmp(arg, "-segprot") == 0 ) { | |
837 | // FIX FIX | |
838 | i += 3; | |
839 | } | |
840 | else if ( strcmp(arg, "-pagezero_size") == 0 ) { | |
841 | fZeroPageSize = parseAddress(argv[++i]); | |
842 | fZeroPageSize &= (-4096); // page align | |
843 | } | |
844 | else if ( strcmp(arg, "-stack_addr") == 0 ) { | |
845 | fStackAddr = parseAddress(argv[++i]); | |
846 | } | |
847 | else if ( strcmp(arg, "-stack_size") == 0 ) { | |
848 | fStackSize = parseAddress(argv[++i]); | |
849 | } | |
850 | else if ( strcmp(arg, "-sectalign") == 0 ) { | |
851 | addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]); | |
852 | i += 3; | |
853 | } | |
854 | else if ( strcmp(arg, "-sectorder_detail") == 0 ) { | |
855 | // FIX FIX | |
856 | } | |
857 | else if ( strcmp(arg, "-sectobjectsymbols") == 0 ) { | |
858 | // FIX FIX | |
859 | i += 2; | |
860 | } | |
861 | else if ( strcmp(arg, "-bundle_loader") == 0 ) { | |
862 | // FIX FIX | |
863 | ++i; | |
864 | } | |
865 | else if ( strcmp(arg, "-private_bundle") == 0 ) { | |
866 | // FIX FIX | |
867 | } | |
868 | else if ( strcmp(arg, "-twolevel_namespace_hints") == 0 ) { | |
869 | // FIX FIX | |
870 | } | |
871 | else if ( strcmp(arg, "-multiply_defined") == 0 ) { | |
872 | // FIX FIX | |
873 | ++i; | |
874 | } | |
875 | else if ( strcmp(arg, "-multiply_defined_unused") == 0 ) { | |
876 | // FIX FIX | |
877 | ++i; | |
878 | } | |
879 | else if ( strcmp(arg, "-nomultidefs") == 0 ) { | |
880 | // FIX FIX | |
881 | } | |
882 | else if ( arg[1] == 'y' ) { | |
883 | // FIX FIX | |
884 | } | |
885 | else if ( strcmp(arg, "-Y") == 0 ) { | |
886 | ++i; | |
887 | // FIX FIX | |
888 | } | |
889 | else if ( strcmp(arg, "-m") == 0 ) { | |
890 | // FIX FIX | |
891 | } | |
892 | else if ( strcmp(arg, "-whyload") == 0 ) { | |
893 | // FIX FIX | |
894 | } | |
895 | else if ( strcmp(arg, "-u") == 0 ) { | |
896 | const char* name = argv[++i]; | |
897 | if ( name == NULL ) | |
898 | throw "-u missing argument"; | |
899 | fInitialUndefines.push_back(name); | |
900 | } | |
901 | else if ( strcmp(arg, "-i") == 0 ) { | |
902 | // FIX FIX | |
903 | } | |
904 | else if ( strcmp(arg, "-U") == 0 ) { | |
905 | // FIX FIX | |
906 | ++i; | |
907 | } | |
908 | else if ( strcmp(arg, "-s") == 0 ) { | |
909 | // FIX FIX | |
910 | } | |
911 | else if ( strcmp(arg, "-x") == 0 ) { | |
912 | // FIX FIX | |
913 | } | |
914 | else if ( strcmp(arg, "-S") == 0 ) { | |
915 | // FIX FIX | |
916 | } | |
917 | else if ( strcmp(arg, "-X") == 0 ) { | |
918 | // FIX FIX | |
919 | } | |
920 | else if ( strcmp(arg, "-Si") == 0 ) { | |
921 | // FIX FIX | |
922 | } | |
923 | else if ( strcmp(arg, "-b") == 0 ) { | |
924 | // FIX FIX | |
925 | } | |
926 | else if ( strcmp(arg, "-Sn") == 0 ) { | |
927 | // FIX FIX | |
928 | } | |
929 | else if ( strcmp(arg, "-dead_strip") == 0 ) { | |
930 | // FIX FIX | |
931 | fprintf(stderr, "ld64: warning -dead_strip not yet supported for 64-bit code\n"); | |
932 | } | |
933 | else if ( strcmp(arg, "-v") == 0 ) { | |
934 | extern const char ld64VersionString[]; | |
935 | fprintf(stderr, "%s", ld64VersionString); | |
936 | // if only -v specified, exit cleanly | |
937 | if ( argc == 2 ) | |
938 | exit(0); | |
939 | } | |
940 | else if ( strcmp(arg, "-w") == 0 ) { | |
941 | // FIX FIX | |
942 | } | |
943 | else if ( strcmp(arg, "-arch_errors_fatal") == 0 ) { | |
944 | // FIX FIX | |
945 | } | |
946 | else if ( strcmp(arg, "-M") == 0 ) { | |
947 | // FIX FIX | |
948 | } | |
949 | else if ( strcmp(arg, "-whatsloaded") == 0 ) { | |
950 | // FIX FIX | |
951 | } | |
952 | else if ( strcmp(arg, "-headerpad") == 0 ) { | |
953 | const char* size = argv[++i]; | |
954 | if ( size == NULL ) | |
955 | throw "-headerpad missing argument"; | |
956 | fMinimumHeaderPad = parseAddress(size); | |
957 | } | |
958 | else if ( strcmp(arg, "-headerpad_max_install_names") == 0 ) { | |
959 | // FIX FIX | |
960 | } | |
961 | else if ( strcmp(arg, "-t") == 0 ) { | |
962 | // FIX FIX | |
963 | } | |
964 | else if ( strcmp(arg, "-A") == 0 ) { | |
965 | // FIX FIX | |
966 | ++i; | |
967 | } | |
968 | else if ( strcmp(arg, "-umbrella") == 0 ) { | |
969 | const char* name = argv[++i]; | |
970 | if ( name == NULL ) | |
971 | throw "-umbrella missing argument"; | |
972 | fUmbrellaName = name; | |
973 | } | |
974 | else if ( strcmp(arg, "-allowable_client") == 0 ) { | |
975 | // FIX FIX | |
976 | ++i; | |
977 | } | |
978 | else if ( strcmp(arg, "-client_name") == 0 ) { | |
979 | // FIX FIX | |
980 | ++i; | |
981 | } | |
982 | else if ( strcmp(arg, "-sub_umbrella") == 0 ) { | |
983 | const char* name = argv[++i]; | |
984 | if ( name == NULL ) | |
985 | throw "-sub_umbrella missing argument"; | |
986 | fSubUmbellas.push_back(name); | |
987 | } | |
988 | else if ( strcmp(arg, "-sub_library") == 0 ) { | |
989 | const char* name = argv[++i]; | |
990 | if ( name == NULL ) | |
991 | throw "-sub_library missing argument"; | |
992 | fSubLibraries.push_back(name); | |
993 | } | |
994 | else if ( strcmp(arg, "-init") == 0 ) { | |
995 | const char* name = argv[++i]; | |
996 | if ( name == NULL ) | |
997 | throw "-init missing argument"; | |
998 | fInitFunctionName = name; | |
999 | } | |
1000 | else if ( strcmp(arg, "-warn_commons") == 0 ) { | |
1001 | fWarnCommons = true; | |
1002 | } | |
1003 | else if ( strcmp(arg, "-commons") == 0 ) { | |
1004 | fCommonsMode = parseCommonsTreatment(argv[++i]); | |
1005 | } | |
1006 | ||
1007 | else { | |
1008 | fprintf(stderr, "unknown option: %s\n", arg); | |
1009 | } | |
1010 | } | |
1011 | else { | |
1012 | fInputFiles.push_back(makeFileInfo(arg)); | |
1013 | } | |
1014 | } | |
1015 | } | |
1016 | ||
1017 | void Options::buildSearchPaths(int argc, const char* argv[]) | |
1018 | { | |
1019 | bool addStandardLibraryDirectories = true; | |
1020 | // scan through argv looking for -L and -F options | |
1021 | for(int i=0; i < argc; ++i) { | |
1022 | if ( (argv[i][0] == '-') && (argv[i][1] == 'L') ) | |
1023 | fLibrarySearchPaths.push_back(&argv[i][2]); | |
1024 | else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') ) | |
1025 | fFrameworkSearchPaths.push_back(&argv[i][2]); | |
1026 | else if ( strcmp(argv[i], "-Z") == 0 ) | |
1027 | addStandardLibraryDirectories = false; | |
1028 | } | |
1029 | if ( addStandardLibraryDirectories ) { | |
1030 | fLibrarySearchPaths.push_back("/usr/lib"); | |
1031 | fLibrarySearchPaths.push_back("/usr/local/lib"); | |
1032 | ||
1033 | fFrameworkSearchPaths.push_back("/Library/Frameworks/"); | |
1034 | fFrameworkSearchPaths.push_back("/Network/Library/Frameworks/"); | |
1035 | fFrameworkSearchPaths.push_back("/System/Library/Frameworks/"); | |
1036 | } | |
1037 | } | |
1038 | ||
1039 | // this is run before the command line is parsed | |
1040 | void Options::parsePreCommandLineEnvironmentSettings() | |
1041 | { | |
1042 | if ( getenv("RC_TRACE_ARCHIVES") != NULL) | |
1043 | fReaderOptions.fTraceArchives = true; | |
1044 | ||
1045 | if ( getenv("RC_TRACE_DYLIBS") != NULL) { | |
1046 | fReaderOptions.fTraceDylibs = true; | |
1047 | fReaderOptions.fTraceIndirectDylibs = true; | |
1048 | } | |
1049 | } | |
1050 | ||
1051 | // this is run after the command line is parsed | |
1052 | void Options::parsePostCommandLineEnvironmentSettings() | |
1053 | { | |
1054 | ||
1055 | } | |
1056 | ||
1057 | void Options::checkIllegalOptionCombinations() | |
1058 | { | |
1059 | // check -undefined setting | |
1060 | switch ( fUndefinedTreatment ) { | |
1061 | case kUndefinedError: | |
1062 | case kUndefinedDynamicLookup: | |
1063 | // always legal | |
1064 | break; | |
1065 | case kUndefinedWarning: | |
1066 | case kUndefinedSuppress: | |
1067 | // requires flat namespace | |
1068 | if ( fNameSpace == kTwoLevelNameSpace ) | |
1069 | throw "can't use -undefined warning or suppress with -twolevel_namespace"; | |
1070 | break; | |
1071 | } | |
1072 | ||
1073 | // unify -sub_umbrella with dylibs | |
1074 | for (std::vector<const char*>::iterator it = fSubUmbellas.begin(); it != fSubUmbellas.end(); it++) { | |
1075 | const char* subUmbrella = *it; | |
1076 | bool found = false; | |
1077 | for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) { | |
1078 | Options::FileInfo& info = *fit; | |
1079 | const char* lastSlash = strrchr(info.path, '/'); | |
1080 | if ( lastSlash == NULL ) | |
1081 | lastSlash = info.path - 1; | |
1082 | if ( strcmp(&lastSlash[1], subUmbrella) == 0 ) { | |
1083 | info.options.fReExport = true; | |
1084 | found = true; | |
1085 | break; | |
1086 | } | |
1087 | } | |
1088 | if ( ! found ) | |
1089 | fprintf(stderr, "ld64 warning: -sub_umbrella %s does not match a supplied dylib\n", subUmbrella); | |
1090 | } | |
1091 | ||
1092 | // unify -sub_library with dylibs | |
1093 | for (std::vector<const char*>::iterator it = fSubLibraries.begin(); it != fSubLibraries.end(); it++) { | |
1094 | const char* subLibrary = *it; | |
1095 | bool found = false; | |
1096 | for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) { | |
1097 | Options::FileInfo& info = *fit; | |
1098 | const char* lastSlash = strrchr(info.path, '/'); | |
1099 | if ( lastSlash == NULL ) | |
1100 | lastSlash = info.path - 1; | |
1101 | const char* dot = strchr(lastSlash, '.'); | |
1102 | if ( dot == NULL ) | |
1103 | dot = &lastSlash[strlen(lastSlash)]; | |
1104 | if ( strncmp(&lastSlash[1], subLibrary, dot-lastSlash-1) == 0 ) { | |
1105 | info.options.fReExport = true; | |
1106 | found = true; | |
1107 | break; | |
1108 | } | |
1109 | } | |
1110 | if ( ! found ) | |
1111 | fprintf(stderr, "ld64 warning: -sub_library %s does not match a supplied dylib\n", subLibrary); | |
1112 | } | |
1113 | ||
1114 | // sync reader options | |
1115 | if ( fNameSpace != kTwoLevelNameSpace ) | |
1116 | fReaderOptions.fFlatNamespace = true; | |
1117 | ||
1118 | // check -stack_addr | |
1119 | if ( fStackAddr != 0 ) { | |
1120 | switch (fArchitecture) { | |
1121 | case CPU_TYPE_I386: | |
1122 | case CPU_TYPE_POWERPC: | |
1123 | if ( fStackAddr > 0xFFFFFFFF ) | |
1124 | throw "-stack_addr must be < 4G for 32-bit processes"; | |
1125 | break; | |
1126 | case CPU_TYPE_POWERPC64: | |
1127 | break; | |
1128 | } | |
1129 | if ( (fStackAddr & -4096) != fStackAddr ) | |
1130 | throw "-stack_addr must be multiples of 4K"; | |
1131 | if ( fStackSize == 0 ) | |
1132 | throw "-stack_addr must be used with -stack_size"; | |
1133 | } | |
1134 | ||
1135 | // check -stack_size | |
1136 | if ( fStackSize != 0 ) { | |
1137 | switch (fArchitecture) { | |
1138 | case CPU_TYPE_I386: | |
1139 | case CPU_TYPE_POWERPC: | |
1140 | if ( fStackSize > 0xFFFFFFFF ) | |
1141 | throw "-stack_size must be < 4G for 32-bit processes"; | |
1142 | if ( fStackAddr == 0 ) { | |
1143 | fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0xC0000000\n"); | |
1144 | fStackAddr = 0xC0000000; | |
1145 | } | |
1146 | break; | |
1147 | case CPU_TYPE_POWERPC64: | |
1148 | if ( fStackAddr == 0 ) { | |
1149 | fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0x0008000000000000\n"); | |
1150 | fStackAddr = 0x0008000000000000LL; | |
1151 | } | |
1152 | break; | |
1153 | } | |
1154 | if ( (fStackSize & -4096) != fStackSize ) | |
1155 | throw "-stack_size must be multiples of 4K"; | |
1156 | switch ( fOutputKind ) { | |
1157 | case Options::kDynamicExecutable: | |
1158 | case Options::kStaticExecutable: | |
1159 | // custom stack size only legeal when building main executable | |
1160 | break; | |
1161 | case Options::kDynamicLibrary: | |
1162 | case Options::kDynamicBundle: | |
1163 | case Options::kObjectFile: | |
1164 | case Options::kDyld: | |
1165 | throw "-stack_size option can only be used when linking a main executable"; | |
1166 | } | |
1167 | } | |
1168 | ||
1169 | // check -init is only used when building a dylib | |
1170 | if ( (fInitFunctionName != NULL) && (fOutputKind != Options::kDynamicLibrary) ) | |
1171 | throw "-init can only be used with -dynamiclib"; | |
1172 | } | |
1173 | ||
1174 |