mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-14 14:56:47 +00:00
[lld-macho] Implement -ObjC
It's roughly like -force_load with some filtering. Differential Revision: https://reviews.llvm.org/D86181
This commit is contained in:
parent
7394460d87
commit
cf918c809b
@ -10,6 +10,7 @@ add_lld_library(lldMachO2
|
||||
InputFiles.cpp
|
||||
InputSection.cpp
|
||||
MergedOutputSection.cpp
|
||||
ObjC.cpp
|
||||
OutputSection.cpp
|
||||
OutputSegment.cpp
|
||||
SymbolTable.cpp
|
||||
|
@ -33,6 +33,7 @@ struct PlatformInfo {
|
||||
struct Configuration {
|
||||
Symbol *entry;
|
||||
bool hasReexports = false;
|
||||
bool forceLoadObjC = false;
|
||||
uint32_t headerPad;
|
||||
llvm::StringRef installName;
|
||||
llvm::StringRef outputFile;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "Config.h"
|
||||
#include "DriverUtils.h"
|
||||
#include "InputFiles.h"
|
||||
#include "ObjC.h"
|
||||
#include "OutputSection.h"
|
||||
#include "OutputSegment.h"
|
||||
#include "SymbolTable.h"
|
||||
@ -210,6 +211,29 @@ static void getFrameworkSearchPaths(opt::InputArgList &args,
|
||||
{"/Library/Frameworks", "/System/Library/Frameworks"});
|
||||
}
|
||||
|
||||
// Returns slices of MB by parsing MB as an archive file.
|
||||
// Each slice consists of a member file in the archive.
|
||||
static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef mb) {
|
||||
std::unique_ptr<Archive> file =
|
||||
CHECK(Archive::create(mb),
|
||||
mb.getBufferIdentifier() + ": failed to parse archive");
|
||||
|
||||
std::vector<MemoryBufferRef> v;
|
||||
Error err = Error::success();
|
||||
for (const Archive::Child &c : file->children(err)) {
|
||||
MemoryBufferRef mbref =
|
||||
CHECK(c.getMemoryBufferRef(),
|
||||
mb.getBufferIdentifier() +
|
||||
": could not get the buffer for a child of the archive");
|
||||
v.push_back(mbref);
|
||||
}
|
||||
if (err)
|
||||
fatal(mb.getBufferIdentifier() +
|
||||
": Archive::children failed: " + toString(std::move(err)));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void addFile(StringRef path) {
|
||||
Optional<MemoryBufferRef> buffer = readFile(path);
|
||||
if (!buffer)
|
||||
@ -224,6 +248,21 @@ static void addFile(StringRef path) {
|
||||
if (!file->isEmpty() && !file->hasSymbolTable())
|
||||
error(path + ": archive has no index; run ranlib to add one");
|
||||
|
||||
if (config->forceLoadObjC) {
|
||||
for (const object::Archive::Symbol &sym : file->symbols())
|
||||
if (sym.getName().startswith(objc::klass))
|
||||
symtab->addUndefined(sym.getName());
|
||||
|
||||
// TODO: no need to look for ObjC sections for a given archive member if
|
||||
// we already found that it contains an ObjC symbol. We should also
|
||||
// consider creating a LazyObjFile class in order to avoid double-loading
|
||||
// these files here and below (as part of the ArchiveFile).
|
||||
if (Optional<MemoryBufferRef> buffer = readFile(path))
|
||||
for (MemoryBufferRef member : getArchiveMembers(*buffer))
|
||||
if (hasObjCSection(member))
|
||||
inputFiles.push_back(make<ObjFile>(member));
|
||||
}
|
||||
|
||||
inputFiles.push_back(make<ArchiveFile>(std::move(file)));
|
||||
break;
|
||||
}
|
||||
@ -254,29 +293,6 @@ static void addFileList(StringRef path) {
|
||||
addFile(path);
|
||||
}
|
||||
|
||||
// Returns slices of MB by parsing MB as an archive file.
|
||||
// Each slice consists of a member file in the archive.
|
||||
static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef mb) {
|
||||
std::unique_ptr<Archive> file =
|
||||
CHECK(Archive::create(mb),
|
||||
mb.getBufferIdentifier() + ": failed to parse archive");
|
||||
|
||||
std::vector<MemoryBufferRef> v;
|
||||
Error err = Error::success();
|
||||
for (const Archive::Child &c : file->children(err)) {
|
||||
MemoryBufferRef mbref =
|
||||
CHECK(c.getMemoryBufferRef(),
|
||||
mb.getBufferIdentifier() +
|
||||
": could not get the buffer for a child of the archive");
|
||||
v.push_back(mbref);
|
||||
}
|
||||
if (err)
|
||||
fatal(mb.getBufferIdentifier() +
|
||||
": Archive::children failed: " + toString(std::move(err)));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void forceLoadArchive(StringRef path) {
|
||||
if (Optional<MemoryBufferRef> buffer = readFile(path))
|
||||
for (MemoryBufferRef member : getArchiveMembers(*buffer))
|
||||
@ -517,6 +533,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
|
||||
|
||||
getLibrarySearchPaths(args, roots, config->librarySearchPaths);
|
||||
getFrameworkSearchPaths(args, roots, config->frameworkSearchPaths);
|
||||
config->forceLoadObjC = args.hasArg(OPT_ObjC);
|
||||
|
||||
if (args.hasArg(OPT_v)) {
|
||||
message(getLLDVersion());
|
||||
@ -571,6 +588,7 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
|
||||
case OPT_e:
|
||||
case OPT_F:
|
||||
case OPT_L:
|
||||
case OPT_ObjC:
|
||||
case OPT_headerpad:
|
||||
case OPT_install_name:
|
||||
case OPT_rpath:
|
||||
|
@ -47,7 +47,9 @@
|
||||
#include "ExportTrie.h"
|
||||
#include "InputSection.h"
|
||||
#include "MachOStructs.h"
|
||||
#include "ObjC.h"
|
||||
#include "OutputSection.h"
|
||||
#include "OutputSegment.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "Symbols.h"
|
||||
#include "Target.h"
|
||||
@ -116,7 +118,7 @@ Optional<MemoryBufferRef> macho::readFile(StringRef path) {
|
||||
return None;
|
||||
}
|
||||
|
||||
static const load_command *findCommand(const mach_header_64 *hdr,
|
||||
const load_command *macho::findCommand(const mach_header_64 *hdr,
|
||||
uint32_t type) {
|
||||
const uint8_t *p =
|
||||
reinterpret_cast<const uint8_t *>(hdr) + sizeof(mach_header_64);
|
||||
@ -137,8 +139,10 @@ void InputFile::parseSections(ArrayRef<section_64> sections) {
|
||||
for (const section_64 &sec : sections) {
|
||||
InputSection *isec = make<InputSection>();
|
||||
isec->file = this;
|
||||
isec->name = StringRef(sec.sectname, strnlen(sec.sectname, 16));
|
||||
isec->segname = StringRef(sec.segname, strnlen(sec.segname, 16));
|
||||
isec->name =
|
||||
StringRef(sec.sectname, strnlen(sec.sectname, sizeof(sec.sectname)));
|
||||
isec->segname =
|
||||
StringRef(sec.segname, strnlen(sec.segname, sizeof(sec.segname)));
|
||||
isec->data = {isZeroFill(sec.flags) ? nullptr : buf + sec.offset,
|
||||
static_cast<size_t>(sec.size)};
|
||||
if (sec.align >= 32)
|
||||
@ -474,14 +478,14 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella)
|
||||
case SymbolKind::ObjectiveCClass:
|
||||
// XXX ld64 only creates these symbols when -ObjC is passed in. We may
|
||||
// want to emulate that.
|
||||
addSymbol("_OBJC_CLASS_$_" + symbol->getName());
|
||||
addSymbol("_OBJC_METACLASS_$_" + symbol->getName());
|
||||
addSymbol(objc::klass + symbol->getName());
|
||||
addSymbol(objc::metaclass + symbol->getName());
|
||||
break;
|
||||
case SymbolKind::ObjectiveCClassEHType:
|
||||
addSymbol("_OBJC_EHTYPE_$_" + symbol->getName());
|
||||
addSymbol(objc::ehtype + symbol->getName());
|
||||
break;
|
||||
case SymbolKind::ObjectiveCInstanceVariable:
|
||||
addSymbol("_OBJC_IVAR_$_" + symbol->getName());
|
||||
addSymbol(objc::ivar + symbol->getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +128,9 @@ extern std::vector<InputFile *> inputFiles;
|
||||
|
||||
llvm::Optional<MemoryBufferRef> readFile(StringRef path);
|
||||
|
||||
const llvm::MachO::load_command *
|
||||
findCommand(const llvm::MachO::mach_header_64 *, uint32_t type);
|
||||
|
||||
} // namespace macho
|
||||
|
||||
std::string toString(const macho::InputFile *file);
|
||||
|
36
lld/MachO/ObjC.cpp
Normal file
36
lld/MachO/ObjC.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//===- ObjC.cpp -----------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ObjC.h"
|
||||
#include "InputFiles.h"
|
||||
#include "OutputSegment.h"
|
||||
|
||||
#include "llvm/BinaryFormat/MachO.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::MachO;
|
||||
using namespace lld;
|
||||
|
||||
bool macho::hasObjCSection(MemoryBufferRef mb) {
|
||||
auto *hdr = reinterpret_cast<const mach_header_64 *>(mb.getBufferStart());
|
||||
if (const load_command *cmd = findCommand(hdr, LC_SEGMENT_64)) {
|
||||
auto *c = reinterpret_cast<const segment_command_64 *>(cmd);
|
||||
auto sectionHeaders = ArrayRef<section_64>{
|
||||
reinterpret_cast<const section_64 *>(c + 1), c->nsects};
|
||||
for (const section_64 &sec : sectionHeaders) {
|
||||
StringRef sectname(sec.sectname,
|
||||
strnlen(sec.sectname, sizeof(sec.sectname)));
|
||||
StringRef segname(sec.segname, strnlen(sec.segname, sizeof(sec.segname)));
|
||||
if ((segname == segment_names::data && sectname == "__objc_catlist") ||
|
||||
(segname == segment_names::text && sectname == "__swift")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
31
lld/MachO/ObjC.h
Normal file
31
lld/MachO/ObjC.h
Normal file
@ -0,0 +1,31 @@
|
||||
//===- ObjC.h ---------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_MACHO_OBJC_H
|
||||
#define LLD_MACHO_OBJC_H
|
||||
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
|
||||
namespace lld {
|
||||
namespace macho {
|
||||
|
||||
namespace objc {
|
||||
|
||||
constexpr const char klass[] = "_OBJC_CLASS_$_";
|
||||
constexpr const char metaclass[] = "_OBJC_METACLASS_$_";
|
||||
constexpr const char ehtype[] = "_OBJC_EHTYPE_$_";
|
||||
constexpr const char ivar[] = "_OBJC_IVAR_$_";
|
||||
|
||||
} // namespace objc
|
||||
|
||||
bool hasObjCSection(llvm::MemoryBufferRef);
|
||||
|
||||
} // namespace macho
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
63
lld/test/MachO/objc.s
Normal file
63
lld/test/MachO/objc.s
Normal file
@ -0,0 +1,63 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: split-file %s %t
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/has-objc-symbol.s -o %t/has-objc-symbol.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/has-objc-category.s -o %t/has-objc-category.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/has-swift.s -o %t/has-swift.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/no-objc.s -o %t/no-objc.o
|
||||
|
||||
# RUN: rm -f %t/libHasSomeObjC.a
|
||||
# RUN: llvm-ar rcs %t/libHasSomeObjC.a %t/has-objc-symbol.o %t/has-objc-category.o %t/has-swift.o %t/no-objc.o
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
|
||||
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem %t/test.o -o %t/test \
|
||||
# RUN: -L%t -lHasSomeObjC -ObjC
|
||||
# RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=OBJC
|
||||
|
||||
# OBJC: Sections:
|
||||
# OBJC-NEXT: Idx Name Size VMA Type
|
||||
# OBJC-NEXT: 0 __text {{.*}} TEXT
|
||||
# OBJC-NEXT: 1 __swift {{.*}} DATA
|
||||
# OBJC-NEXT: 2 __objc_catlist {{.*}} DATA
|
||||
# OBJC-EMPTY:
|
||||
# OBJC-NEXT: SYMBOL TABLE:
|
||||
# OBJC-NEXT: g F __TEXT,__text _main
|
||||
# OBJC-NEXT: g F __TEXT,__text _OBJC_CLASS_$_MyObject
|
||||
|
||||
# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem %t/test.o -o %t/test \
|
||||
# RUN: -L%t -lHasObjCSymbol -lHasObjCCategory -lHasSwift
|
||||
# RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=NO-OBJC
|
||||
|
||||
# NO-OBJC: Sections:
|
||||
# NO-OBJC-NEXT: Idx Name Size VMA Type
|
||||
# NO-OBJC-NEXT: 0 __text {{.*}} TEXT
|
||||
# NO-OBJC-EMPTY:
|
||||
# NO-OBJC-NEXT: SYMBOL TABLE:
|
||||
# NO-OBJC-NEXT: g F __TEXT,__text _main
|
||||
# NO-OBJC-EMPTY:
|
||||
|
||||
#--- has-objc-symbol.s
|
||||
.globl _OBJC_CLASS_$_MyObject
|
||||
_OBJC_CLASS_$_MyObject:
|
||||
|
||||
#--- has-objc-category.s
|
||||
.section __DATA,__objc_catlist
|
||||
.quad 0x1234
|
||||
|
||||
#--- has-swift.s
|
||||
.section __TEXT,__swift
|
||||
.quad 0x1234
|
||||
|
||||
#--- no-objc.s
|
||||
## This archive member should not be pulled in since it does not contain any
|
||||
## ObjC-related data.
|
||||
.globl _foo
|
||||
.section __DATA,foo
|
||||
|
||||
foo:
|
||||
.quad 0x1234
|
||||
|
||||
#--- test.s
|
||||
.globl _main
|
||||
_main:
|
||||
ret
|
Loading…
x
Reference in New Issue
Block a user