#include "macho_relocatable_file.h"
#include "lto_file.h"
+// #defines are a work around for <rdar://problem/8760268>
+#define __STDC_LIMIT_MACROS 1
+#define __STDC_CONSTANT_MACROS 1
#include "llvm-c/lto.h"
InternalAtom(class File& f);
// overrides of ld::Atom
virtual ld::File* file() const { return &_file; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return "import-atom"; }
virtual uint64_t size() const { return 0; }
virtual uint64_t objectAddress() const { return 0; }
class File : public ld::relocatable::File
{
public:
- File(const char* path, time_t mTime, const uint8_t* content,
- uint32_t contentLength, uint32_t ordinal, cpu_type_t arch);
+ File(const char* path, time_t mTime, ld::File::Ordinal ordinal,
+ const uint8_t* content, uint32_t contentLength, cpu_type_t arch);
virtual ~File();
// overrides of ld::File
virtual uint32_t cpuSubType() const { return _cpuSubType; }
// overrides of ld::relocatable::File
- virtual bool objcReplacementClasses() const { return false; }
virtual DebugInfoKind debugInfo() const { return _debugInfo; }
virtual const char* debugInfoPath() const { return _debugInfoPath; }
virtual time_t debugInfoModificationTime() const
{
public:
Atom(File& f, const char* name, ld::Atom::Scope s,
- ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a);
+ ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a, bool ah);
// overrides of ld::Atom
virtual ld::File* file() const { return &_file; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return (_compiledAtom ? _compiledAtom->translationUnitSource(dir, nm) : false); }
+ virtual const char* translationUnitSource() const
+ { return (_compiledAtom ? _compiledAtom->translationUnitSource() : NULL); }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return (_compiledAtom ? _compiledAtom->size() : 0); }
virtual uint64_t objectAddress() const { return (_compiledAtom ? _compiledAtom->objectAddress() : 0); }
static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch);
static const char* fileKind(const uint8_t* fileContent, uint64_t fileLength);
static File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
- time_t modTime, uint32_t ordinal, cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
+ time_t modTime, ld::File::Ordinal ordinal, cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
static bool libLTOisLoaded() { return (::lto_get_version() != NULL); }
static bool optimize( const std::vector<const ld::Atom*>& allAtoms,
ld::Internal& state,
- uint32_t nextInputOrdinal,
const OptimizeOptions& options,
ld::File::AtomHandler& handler,
std::vector<const ld::Atom*>& newAtoms,
private:
static const char* tripletPrefixForArch(cpu_type_t arch);
- static ld::relocatable::File* parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, const OptimizeOptions& options);
+ static ld::relocatable::File* parseMachOFile(const uint8_t* p, size_t len, const OptimizeOptions& options);
class CStringEquals
{
bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch)
{
- switch (architecture) {
- case CPU_TYPE_I386:
- return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "i386-");
- case CPU_TYPE_X86_64:
- return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "x86_64-");
- case CPU_TYPE_ARM:
- switch ( subarch ) {
- case CPU_SUBTYPE_ARM_V6:
- return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "armv6-");
- case CPU_SUBTYPE_ARM_V7:
- return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "thumbv7-");
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( (architecture == t->cpuType) && (!(t->isSubType) || (subarch == t->cpuSubType)) ) {
+ bool result = ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefix);
+ if ( !result ) {
+ // <rdar://problem/8434487> LTO only supports thumbv7 not armv7
+ if ( t->llvmTriplePrefixAlt[0] != '\0' ) {
+ result = ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefixAlt);
+ }
}
- break;
- case CPU_TYPE_POWERPC:
- return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "powerpc-");
+ return result;
+ }
}
return false;
}
const char* Parser::fileKind(const uint8_t* p, uint64_t fileLength)
{
if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) {
- uint32_t arch = LittleEndian::get32(*((uint32_t*)(&p[16])));
- switch (arch) {
- case CPU_TYPE_POWERPC:
- return "ppc";
- case CPU_TYPE_I386:
- return "i386";
- case CPU_TYPE_X86_64:
- return "x86_64";
- case CPU_TYPE_ARM:
- if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, "armv6-") )
- return "armv6";
- if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, "thumbv7-") )
- return "armv7";
- return "arm";
+ cpu_type_t arch = LittleEndian::get32(*((uint32_t*)(&p[16])));
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( arch == t->cpuType ) {
+ if ( t->isSubType ) {
+ if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, t->llvmTriplePrefix) )
+ return t->archName;
+ }
+ else {
+ return t->archName;
+ }
+ }
}
return "unknown bitcode architecture";
}
return NULL;
}
-File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime,
- uint32_t ordinal, cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles)
+File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, ld::File::Ordinal ordinal,
+ cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles)
{
- File* f = new File(path, modTime, fileContent, fileLength, ordinal, architecture);
+ File* f = new File(path, modTime, ordinal, fileContent, fileLength, architecture);
_s_files.push_back(f);
if ( logAllFiles )
printf("%s\n", path);
}
-ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, const OptimizeOptions& options)
+ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, const OptimizeOptions& options)
{
mach_o::relocatable::ParserOptions objOpts;
objOpts.architecture = options.arch;
modTime = statBuffer.st_mtime;
}
- ld::relocatable::File* result = mach_o::relocatable::parse(p, len, path, modTime, nextInputOrdinal, objOpts);
+ ld::relocatable::File* result = mach_o::relocatable::parse(p, len, path, modTime, ld::File::Ordinal::LTOOrdinal(), objOpts);
if ( result != NULL )
return result;
throw "LLVM LTO, file is not of required architecture";
-File::File(const char* pth, time_t mTime, const uint8_t* content, uint32_t contentLength, uint32_t ord, cpu_type_t arch)
- : ld::relocatable::File(pth,mTime,ord), _architecture(arch), _internalAtom(*this),
+File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8_t* content, uint32_t contentLength, cpu_type_t arch)
+ : ld::relocatable::File(pth,mTime,ordinal), _architecture(arch), _internalAtom(*this),
_atomArray(NULL), _atomArrayCount(0), _module(NULL), _debugInfoPath(pth),
_section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO),
_fixupToInternal(0, ld::Fixup::k1of1, ld::Fixup::kindNone, &_internalAtom),
// make LLVM atoms for definitions and a reference for undefines
if ( def != ld::Atom::definitionProxy ) {
ld::Atom::Scope scope;
+ bool autohide = false;
switch ( attr & LTO_SYMBOL_SCOPE_MASK) {
case LTO_SYMBOL_SCOPE_INTERNAL:
scope = ld::Atom::scopeTranslationUnit;
case LTO_SYMBOL_SCOPE_DEFAULT:
scope = ld::Atom::scopeGlobal;
break;
+#if LTO_API_VERSION >= 4
+ case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN:
+ scope = ld::Atom::scopeGlobal;
+ autohide = true;
+ break;
+#endif
default:
throwf("unknown scope for symbol %s in bitcode file %s", name, pth);
}
continue;
uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK);
// make Atom using placement new operator
- new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, combine, alignment);
- if ( scope == ld::Atom::scopeLinkageUnit )
+ new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, combine, alignment, autohide);
+ if ( scope != ld::Atom::scopeTranslationUnit )
_internalAtom.addReference(name);
if ( log ) fprintf(stderr, "\t0x%08X %s\n", attr, name);
}
{
}
-Atom::Atom(File& f, const char* nm, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a)
+Atom::Atom(File& f, const char* nm, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Combine c,
+ ld::Atom::Alignment a, bool ah)
: ld::Atom(f._section, d, c, s, ld::Atom::typeLTOtemporary,
ld::Atom::symbolTableIn, false, false, false, a),
_file(f), _name(nm), _compiledAtom(NULL)
{
+ if ( ah )
+ this->setAutoHide();
}
void Atom::setCompiledAtom(const ld::Atom& atom)
bool Parser::optimize( const std::vector<const ld::Atom*>& allAtoms,
ld::Internal& state,
- uint32_t nextInputOrdinal,
const OptimizeOptions& options,
ld::File::AtomHandler& handler,
std::vector<const ld::Atom*>& newAtoms,
// 1 - atom scope is global (and not linkage unit).
// 2 - included in nonLLVMRefs set.
// If a symbol is not listed in exportList then LTO is free to optimize it away.
- if ( (atom->scope() == ld::Atom::scopeGlobal) ) {
+ if ( (atom->scope() == ld::Atom::scopeGlobal) && options.preserveAllGlobals ) {
if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name);
::lto_codegen_add_must_preserve_symbol(generator, name);
}
}
// parse generated mach-o file into a MachOReader
- ld::relocatable::File* machoFile = parseMachOFile(machOFile, machOFileLen, nextInputOrdinal, options);
+ ld::relocatable::File* machoFile = parseMachOFile(machOFile, machOFileLen, options);
// sync generated mach-o atoms with existing atoms ld knows about
if ( logAtomsBeforeSync ) {
}
+class Mutex {
+ static pthread_mutex_t lto_lock;
+public:
+ Mutex() { pthread_mutex_lock(<o_lock); }
+ ~Mutex() { pthread_mutex_unlock(<o_lock); }
+};
+pthread_mutex_t Mutex::lto_lock = PTHREAD_MUTEX_INITIALIZER;
//
// Used by archive reader to see if member is an llvm bitcode file
//
bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch)
{
+ Mutex lock;
return Parser::validFile(fileContent, fileLength, architecture, subarch);
}
// main function used by linker to instantiate ld::Files
//
ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
- const char* path, time_t modTime, uint32_t ordinal,
+ const char* path, time_t modTime, ld::File::Ordinal ordinal,
cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles)
{
+ Mutex lock;
if ( Parser::validFile(fileContent, fileLength, architecture, subarch) )
return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles);
else
//
const char* version()
{
+ Mutex lock;
return ::lto_get_version();
}
//
bool libLTOisLoaded()
{
+ Mutex lock;
return (::lto_get_version() != NULL);
}
//
const char* archName(const uint8_t* fileContent, uint64_t fileLength)
{
+ Mutex lock;
return Parser::fileKind(fileContent, fileLength);
}
//
bool optimize( const std::vector<const ld::Atom*>& allAtoms,
ld::Internal& state,
- uint32_t nextInputOrdinal,
const OptimizeOptions& options,
ld::File::AtomHandler& handler,
std::vector<const ld::Atom*>& newAtoms,
std::vector<const char*>& additionalUndefines)
{
- return Parser::optimize(allAtoms, state, nextInputOrdinal, options, handler, newAtoms, additionalUndefines);
+ Mutex lock;
+ return Parser::optimize(allAtoms, state, options, handler, newAtoms, additionalUndefines);
}