[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / llvm / tools / llvm-libtool-darwin / llvm-libtool-darwin.cpp
blob82c46882373563232caff858db83356846f3dcf0
1 //===-- llvm-libtool-darwin.cpp - a tool for creating libraries -----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // A utility for creating static and dynamic libraries for Darwin.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/BinaryFormat/Magic.h"
14 #include "llvm/IR/LLVMContext.h"
15 #include "llvm/Object/ArchiveWriter.h"
16 #include "llvm/Object/IRObjectFile.h"
17 #include "llvm/Object/MachO.h"
18 #include "llvm/Object/MachOUniversal.h"
19 #include "llvm/Object/MachOUniversalWriter.h"
20 #include "llvm/Object/ObjectFile.h"
21 #include "llvm/Support/CommandLine.h"
22 #include "llvm/Support/InitLLVM.h"
23 #include "llvm/Support/LineIterator.h"
24 #include "llvm/Support/VirtualFileSystem.h"
25 #include "llvm/Support/WithColor.h"
26 #include "llvm/TextAPI/Architecture.h"
27 #include <map>
28 #include <type_traits>
30 using namespace llvm;
31 using namespace llvm::object;
33 static LLVMContext LLVMCtx;
35 typedef std::map<uint64_t, std::vector<NewArchiveMember>>
36 MembersPerArchitectureMap;
38 cl::OptionCategory LibtoolCategory("llvm-libtool-darwin Options");
40 static cl::opt<std::string> OutputFile("o", cl::desc("Specify output filename"),
41 cl::value_desc("filename"),
42 cl::cat(LibtoolCategory));
44 static cl::list<std::string> InputFiles(cl::Positional,
45 cl::desc("<input files>"),
46 cl::ZeroOrMore,
47 cl::cat(LibtoolCategory));
49 static cl::opt<std::string> ArchType(
50 "arch_only", cl::desc("Specify architecture type for output library"),
51 cl::value_desc("arch_type"), cl::ZeroOrMore, cl::cat(LibtoolCategory));
53 enum class Operation { None, Static };
55 static cl::opt<Operation> LibraryOperation(
56 cl::desc("Library Type: "),
57 cl::values(
58 clEnumValN(Operation::Static, "static",
59 "Produce a statically linked library from the input files")),
60 cl::init(Operation::None), cl::cat(LibtoolCategory));
62 static cl::opt<bool> DeterministicOption(
63 "D", cl::desc("Use zero for timestamps and UIDs/GIDs (Default)"),
64 cl::init(false), cl::cat(LibtoolCategory));
66 static cl::opt<bool>
67 NonDeterministicOption("U", cl::desc("Use actual timestamps and UIDs/GIDs"),
68 cl::init(false), cl::cat(LibtoolCategory));
70 static cl::opt<std::string>
71 FileList("filelist",
72 cl::desc("Pass in file containing a list of filenames"),
73 cl::value_desc("listfile[,dirname]"), cl::cat(LibtoolCategory));
75 static cl::list<std::string> Libraries(
76 "l",
77 cl::desc(
78 "l<x> searches for the library libx.a in the library search path. If"
79 " the string 'x' ends with '.o', then the library 'x' is searched for"
80 " without prepending 'lib' or appending '.a'"),
81 cl::ZeroOrMore, cl::Prefix, cl::cat(LibtoolCategory));
83 static cl::list<std::string> LibrarySearchDirs(
84 "L",
85 cl::desc(
86 "L<dir> adds <dir> to the list of directories in which to search for"
87 " libraries"),
88 cl::ZeroOrMore, cl::Prefix, cl::cat(LibtoolCategory));
90 static cl::opt<bool>
91 VersionOption("V", cl::desc("Print the version number and exit"),
92 cl::cat(LibtoolCategory));
94 static cl::opt<bool> NoWarningForNoSymbols(
95 "no_warning_for_no_symbols",
96 cl::desc("Do not warn about files that have no symbols"),
97 cl::cat(LibtoolCategory), cl::init(false));
99 static const std::array<std::string, 3> StandardSearchDirs{
100 "/lib",
101 "/usr/lib",
102 "/usr/local/lib",
105 struct Config {
106 bool Deterministic = true; // Updated by 'D' and 'U' modifiers.
107 uint32_t ArchCPUType;
108 uint32_t ArchCPUSubtype;
111 static Expected<std::string> searchForFile(const Twine &FileName) {
113 auto FindLib =
114 [FileName](ArrayRef<std::string> SearchDirs) -> Optional<std::string> {
115 for (StringRef Dir : SearchDirs) {
116 SmallString<128> Path;
117 sys::path::append(Path, Dir, FileName);
119 if (sys::fs::exists(Path))
120 return std::string(Path);
122 return None;
125 Optional<std::string> Found = FindLib(LibrarySearchDirs);
126 if (!Found)
127 Found = FindLib(StandardSearchDirs);
128 if (Found)
129 return *Found;
131 return createStringError(std::errc::invalid_argument,
132 "cannot locate file '%s'", FileName.str().c_str());
135 static Error processCommandLineLibraries() {
136 for (StringRef BaseName : Libraries) {
137 Expected<std::string> FullPath = searchForFile(
138 BaseName.endswith(".o") ? BaseName.str() : "lib" + BaseName + ".a");
139 if (!FullPath)
140 return FullPath.takeError();
141 InputFiles.push_back(FullPath.get());
144 return Error::success();
147 static Error processFileList() {
148 StringRef FileName, DirName;
149 std::tie(FileName, DirName) = StringRef(FileList).rsplit(",");
151 ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
152 MemoryBuffer::getFileOrSTDIN(FileName, /*IsText=*/false,
153 /*RequiresNullTerminator=*/false);
154 if (std::error_code EC = FileOrErr.getError())
155 return createFileError(FileName, errorCodeToError(EC));
156 const MemoryBuffer &Ref = *FileOrErr.get();
158 line_iterator I(Ref, /*SkipBlanks=*/false);
159 if (I.is_at_eof())
160 return createStringError(std::errc::invalid_argument,
161 "file list file: '%s' is empty",
162 FileName.str().c_str());
163 for (; !I.is_at_eof(); ++I) {
164 StringRef Line = *I;
165 if (Line.empty())
166 return createStringError(std::errc::invalid_argument,
167 "file list file: '%s': filename cannot be empty",
168 FileName.str().c_str());
170 SmallString<128> Path;
171 if (!DirName.empty())
172 sys::path::append(Path, DirName, Line);
173 else
174 sys::path::append(Path, Line);
175 InputFiles.push_back(static_cast<std::string>(Path));
177 return Error::success();
180 static Error validateArchitectureName(StringRef ArchitectureName) {
181 if (!MachOObjectFile::isValidArch(ArchitectureName)) {
182 std::string Buf;
183 raw_string_ostream OS(Buf);
184 for (StringRef Arch : MachOObjectFile::getValidArchs())
185 OS << Arch << " ";
187 return createStringError(
188 std::errc::invalid_argument,
189 "invalid architecture '%s': valid architecture names are %s",
190 ArchitectureName.str().c_str(), OS.str().c_str());
192 return Error::success();
195 static uint64_t getCPUID(uint32_t CPUType, uint32_t CPUSubtype) {
196 switch (CPUType) {
197 case MachO::CPU_TYPE_ARM:
198 case MachO::CPU_TYPE_ARM64:
199 case MachO::CPU_TYPE_ARM64_32:
200 case MachO::CPU_TYPE_X86_64:
201 // We consider CPUSubtype only for the above 4 CPUTypes to match cctools'
202 // libtool behavior.
203 return static_cast<uint64_t>(CPUType) << 32 | CPUSubtype;
204 default:
205 return CPUType;
209 // MembersData is an organized collection of members.
210 struct MembersData {
211 // MembersPerArchitectureMap is a mapping from CPU architecture to a list of
212 // members.
213 MembersPerArchitectureMap MembersPerArchitecture;
214 std::vector<std::unique_ptr<MemoryBuffer>> FileBuffers;
216 static_assert(!std::is_copy_constructible<NewArchiveMember>::value,
217 "MembersPerArchitecture has a dependency on FileBuffers so it "
218 "should not be able to be copied on its own without "
219 "FileBuffers.");
220 static_assert(!std::is_copy_assignable<NewArchiveMember>::value,
221 "MembersPerArchitecture has a dependency on FileBuffers so it "
222 "should not be able to be copied on its own without "
223 "FileBuffers.");
226 // MembersBuilder collects and organizes all members from the files provided by
227 // the user.
228 class MembersBuilder {
229 public:
230 MembersBuilder(const Config &C) : C(C) {}
232 Expected<MembersData> build() {
233 for (StringRef FileName : InputFiles)
234 if (Error E = addMember(FileName))
235 return std::move(E);
237 if (!ArchType.empty()) {
238 uint64_t ArchCPUID = getCPUID(C.ArchCPUType, C.ArchCPUSubtype);
239 if (Data.MembersPerArchitecture.find(ArchCPUID) ==
240 Data.MembersPerArchitecture.end())
241 return createStringError(std::errc::invalid_argument,
242 "no library created (no object files in input "
243 "files matching -arch_only %s)",
244 ArchType.c_str());
246 return std::move(Data);
249 private:
250 // Check that a file's architecture [FileCPUType, FileCPUSubtype]
251 // matches the architecture specified under -arch_only flag.
252 bool acceptFileArch(uint32_t FileCPUType, uint32_t FileCPUSubtype) {
253 if (C.ArchCPUType != FileCPUType)
254 return false;
256 switch (C.ArchCPUType) {
257 case MachO::CPU_TYPE_ARM:
258 case MachO::CPU_TYPE_ARM64_32:
259 case MachO::CPU_TYPE_X86_64:
260 return C.ArchCPUSubtype == FileCPUSubtype;
262 case MachO::CPU_TYPE_ARM64:
263 if (C.ArchCPUSubtype == MachO::CPU_SUBTYPE_ARM64_ALL)
264 return FileCPUSubtype == MachO::CPU_SUBTYPE_ARM64_ALL ||
265 FileCPUSubtype == MachO::CPU_SUBTYPE_ARM64_V8;
266 else
267 return C.ArchCPUSubtype == FileCPUSubtype;
269 default:
270 return true;
274 Error verifyAndAddMachOObject(NewArchiveMember Member) {
275 auto MBRef = Member.Buf->getMemBufferRef();
276 Expected<std::unique_ptr<object::ObjectFile>> ObjOrErr =
277 object::ObjectFile::createObjectFile(MBRef);
279 // Throw error if not a valid object file.
280 if (!ObjOrErr)
281 return createFileError(Member.MemberName, ObjOrErr.takeError());
283 // Throw error if not in Mach-O format.
284 if (!isa<object::MachOObjectFile>(**ObjOrErr))
285 return createStringError(std::errc::invalid_argument,
286 "'%s': format not supported",
287 Member.MemberName.data());
289 auto *O = dyn_cast<MachOObjectFile>(ObjOrErr->get());
290 uint32_t FileCPUType, FileCPUSubtype;
291 std::tie(FileCPUType, FileCPUSubtype) = MachO::getCPUTypeFromArchitecture(
292 MachO::getArchitectureFromName(O->getArchTriple().getArchName()));
294 // If -arch_only is specified then skip this file if it doesn't match
295 // the architecture specified.
296 if (!ArchType.empty() && !acceptFileArch(FileCPUType, FileCPUSubtype)) {
297 return Error::success();
300 if (!NoWarningForNoSymbols && O->symbols().empty())
301 WithColor::warning() << Member.MemberName + " has no symbols\n";
303 uint64_t FileCPUID = getCPUID(FileCPUType, FileCPUSubtype);
304 Data.MembersPerArchitecture[FileCPUID].push_back(std::move(Member));
305 return Error::success();
308 Error verifyAndAddIRObject(NewArchiveMember Member) {
309 auto MBRef = Member.Buf->getMemBufferRef();
310 Expected<std::unique_ptr<object::IRObjectFile>> IROrErr =
311 object::IRObjectFile::create(MBRef, LLVMCtx);
313 // Throw error if not a valid IR object file.
314 if (!IROrErr)
315 return createFileError(Member.MemberName, IROrErr.takeError());
317 Triple TT = Triple(IROrErr->get()->getTargetTriple());
319 Expected<uint32_t> FileCPUTypeOrErr = MachO::getCPUType(TT);
320 if (!FileCPUTypeOrErr)
321 return FileCPUTypeOrErr.takeError();
323 Expected<uint32_t> FileCPUSubTypeOrErr = MachO::getCPUSubType(TT);
324 if (!FileCPUSubTypeOrErr)
325 return FileCPUSubTypeOrErr.takeError();
327 // If -arch_only is specified then skip this file if it doesn't match
328 // the architecture specified.
329 if (!ArchType.empty() &&
330 !acceptFileArch(*FileCPUTypeOrErr, *FileCPUSubTypeOrErr)) {
331 return Error::success();
334 uint64_t FileCPUID = getCPUID(*FileCPUTypeOrErr, *FileCPUSubTypeOrErr);
335 Data.MembersPerArchitecture[FileCPUID].push_back(std::move(Member));
336 return Error::success();
339 Error addChildMember(const object::Archive::Child &M) {
340 Expected<NewArchiveMember> NewMemberOrErr =
341 NewArchiveMember::getOldMember(M, C.Deterministic);
342 if (!NewMemberOrErr)
343 return NewMemberOrErr.takeError();
344 auto &NewMember = *NewMemberOrErr;
346 file_magic Magic = identify_magic(NewMember.Buf->getBuffer());
348 if (Magic == file_magic::bitcode)
349 return verifyAndAddIRObject(std::move(NewMember));
351 return verifyAndAddMachOObject(std::move(NewMember));
354 Error processArchive(object::Archive &Lib, StringRef FileName) {
355 Error Err = Error::success();
356 for (const object::Archive::Child &Child : Lib.children(Err))
357 if (Error E = addChildMember(Child))
358 return createFileError(FileName, std::move(E));
359 if (Err)
360 return createFileError(FileName, std::move(Err));
362 return Error::success();
365 Error addArchiveMembers(NewArchiveMember NewMember, StringRef FileName) {
366 Expected<std::unique_ptr<Archive>> LibOrErr =
367 object::Archive::create(NewMember.Buf->getMemBufferRef());
368 if (!LibOrErr)
369 return createFileError(FileName, LibOrErr.takeError());
371 if (Error E = processArchive(**LibOrErr, FileName))
372 return E;
374 // Update vector FileBuffers with the MemoryBuffers to transfer
375 // ownership.
376 Data.FileBuffers.push_back(std::move(NewMember.Buf));
377 return Error::success();
380 Error addUniversalMembers(NewArchiveMember NewMember, StringRef FileName) {
381 Expected<std::unique_ptr<MachOUniversalBinary>> BinaryOrErr =
382 MachOUniversalBinary::create(NewMember.Buf->getMemBufferRef());
383 if (!BinaryOrErr)
384 return createFileError(FileName, BinaryOrErr.takeError());
386 auto *UO = BinaryOrErr->get();
387 for (const MachOUniversalBinary::ObjectForArch &O : UO->objects()) {
389 Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrErr =
390 O.getAsObjectFile();
391 if (MachOObjOrErr) {
392 NewArchiveMember NewMember =
393 NewArchiveMember(MachOObjOrErr->get()->getMemoryBufferRef());
394 NewMember.MemberName = sys::path::filename(NewMember.MemberName);
396 if (Error E = verifyAndAddMachOObject(std::move(NewMember)))
397 return E;
398 continue;
401 Expected<std::unique_ptr<IRObjectFile>> IRObjectOrError =
402 O.getAsIRObject(LLVMCtx);
403 if (IRObjectOrError) {
404 // A universal file member can be a MachOObjectFile, an IRObject or an
405 // Archive. In case we can successfully cast the member as an IRObject,
406 // it is safe to throw away the error generated due to casting the
407 // object as a MachOObjectFile.
408 consumeError(MachOObjOrErr.takeError());
410 NewArchiveMember NewMember =
411 NewArchiveMember(IRObjectOrError->get()->getMemoryBufferRef());
412 NewMember.MemberName = sys::path::filename(NewMember.MemberName);
414 if (Error E = verifyAndAddIRObject(std::move(NewMember)))
415 return E;
416 continue;
419 Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive();
420 if (ArchiveOrError) {
421 // A universal file member can be a MachOObjectFile, an IRObject or an
422 // Archive. In case we can successfully cast the member as an Archive,
423 // it is safe to throw away the error generated due to casting the
424 // object as a MachOObjectFile.
425 consumeError(MachOObjOrErr.takeError());
426 consumeError(IRObjectOrError.takeError());
428 if (Error E = processArchive(**ArchiveOrError, FileName))
429 return E;
430 continue;
433 Error CombinedError = joinErrors(
434 ArchiveOrError.takeError(),
435 joinErrors(IRObjectOrError.takeError(), MachOObjOrErr.takeError()));
436 return createFileError(FileName, std::move(CombinedError));
439 // Update vector FileBuffers with the MemoryBuffers to transfer
440 // ownership.
441 Data.FileBuffers.push_back(std::move(NewMember.Buf));
442 return Error::success();
445 Error addMember(StringRef FileName) {
446 Expected<NewArchiveMember> NewMemberOrErr =
447 NewArchiveMember::getFile(FileName, C.Deterministic);
448 if (!NewMemberOrErr)
449 return createFileError(FileName, NewMemberOrErr.takeError());
450 auto &NewMember = *NewMemberOrErr;
452 // For regular archives, use the basename of the object path for the member
453 // name.
454 NewMember.MemberName = sys::path::filename(NewMember.MemberName);
455 file_magic Magic = identify_magic(NewMember.Buf->getBuffer());
457 // Flatten archives.
458 if (Magic == file_magic::archive)
459 return addArchiveMembers(std::move(NewMember), FileName);
461 // Flatten universal files.
462 if (Magic == file_magic::macho_universal_binary)
463 return addUniversalMembers(std::move(NewMember), FileName);
465 // Bitcode files.
466 if (Magic == file_magic::bitcode)
467 return verifyAndAddIRObject(std::move(NewMember));
469 return verifyAndAddMachOObject(std::move(NewMember));
472 MembersData Data;
473 const Config &C;
476 static Expected<SmallVector<Slice, 2>>
477 buildSlices(ArrayRef<OwningBinary<Archive>> OutputBinaries) {
478 SmallVector<Slice, 2> Slices;
480 for (const auto &OB : OutputBinaries) {
481 const Archive &A = *OB.getBinary();
482 Expected<Slice> ArchiveSlice = Slice::create(A, &LLVMCtx);
483 if (!ArchiveSlice)
484 return ArchiveSlice.takeError();
485 Slices.push_back(*ArchiveSlice);
487 return Slices;
490 static Error createStaticLibrary(const Config &C) {
491 MembersBuilder Builder(C);
492 auto DataOrError = Builder.build();
493 if (auto Error = DataOrError.takeError())
494 return Error;
496 const auto &NewMembers = DataOrError->MembersPerArchitecture;
498 if (NewMembers.size() == 1) {
499 return writeArchive(OutputFile, NewMembers.begin()->second,
500 /*WriteSymtab=*/true,
501 /*Kind=*/object::Archive::K_DARWIN, C.Deterministic,
502 /*Thin=*/false);
505 SmallVector<OwningBinary<Archive>, 2> OutputBinaries;
506 for (const std::pair<const uint64_t, std::vector<NewArchiveMember>> &M :
507 NewMembers) {
508 Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrErr =
509 writeArchiveToBuffer(M.second,
510 /*WriteSymtab=*/true,
511 /*Kind=*/object::Archive::K_DARWIN,
512 C.Deterministic,
513 /*Thin=*/false);
514 if (!OutputBufferOrErr)
515 return OutputBufferOrErr.takeError();
516 std::unique_ptr<MemoryBuffer> &OutputBuffer = OutputBufferOrErr.get();
518 Expected<std::unique_ptr<Archive>> ArchiveOrError =
519 Archive::create(OutputBuffer->getMemBufferRef());
520 if (!ArchiveOrError)
521 return ArchiveOrError.takeError();
522 std::unique_ptr<Archive> &A = ArchiveOrError.get();
524 OutputBinaries.push_back(
525 OwningBinary<Archive>(std::move(A), std::move(OutputBuffer)));
528 Expected<SmallVector<Slice, 2>> Slices = buildSlices(OutputBinaries);
529 if (!Slices)
530 return Slices.takeError();
532 llvm::stable_sort(*Slices);
533 return writeUniversalBinary(*Slices, OutputFile);
536 static Expected<Config> parseCommandLine(int Argc, char **Argv) {
537 Config C;
538 cl::ParseCommandLineOptions(Argc, Argv, "llvm-libtool-darwin\n");
540 if (LibraryOperation == Operation::None) {
541 if (!VersionOption) {
542 std::string Error;
543 raw_string_ostream Stream(Error);
544 LibraryOperation.error("must be specified", "", Stream);
545 return createStringError(std::errc::invalid_argument, Error.c_str());
547 return C;
550 if (OutputFile.empty()) {
551 std::string Error;
552 raw_string_ostream Stream(Error);
553 OutputFile.error("must be specified", "o", Stream);
554 return createStringError(std::errc::invalid_argument, Error.c_str());
557 if (DeterministicOption && NonDeterministicOption)
558 return createStringError(std::errc::invalid_argument,
559 "cannot specify both -D and -U flags");
560 else if (NonDeterministicOption)
561 C.Deterministic = false;
563 if (!Libraries.empty())
564 if (Error E = processCommandLineLibraries())
565 return std::move(E);
567 if (!FileList.empty())
568 if (Error E = processFileList())
569 return std::move(E);
571 if (InputFiles.empty())
572 return createStringError(std::errc::invalid_argument,
573 "no input files specified");
575 if (ArchType.getNumOccurrences()) {
576 if (Error E = validateArchitectureName(ArchType))
577 return std::move(E);
579 std::tie(C.ArchCPUType, C.ArchCPUSubtype) =
580 MachO::getCPUTypeFromArchitecture(
581 MachO::getArchitectureFromName(ArchType));
584 return C;
587 int main(int Argc, char **Argv) {
588 InitLLVM X(Argc, Argv);
589 cl::HideUnrelatedOptions({&LibtoolCategory, &getColorCategory()});
590 Expected<Config> ConfigOrErr = parseCommandLine(Argc, Argv);
591 if (!ConfigOrErr) {
592 WithColor::defaultErrorHandler(ConfigOrErr.takeError());
593 return EXIT_FAILURE;
596 if (VersionOption)
597 cl::PrintVersionMessage();
599 Config C = *ConfigOrErr;
600 switch (LibraryOperation) {
601 case Operation::None:
602 break;
603 case Operation::Static:
604 if (Error E = createStaticLibrary(C)) {
605 WithColor::defaultErrorHandler(std::move(E));
606 return EXIT_FAILURE;
608 break;