2014-01-04 07:12:02 +08:00
|
|
|
//===- lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp --------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Linker
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
///
|
|
|
|
/// \file Converts from in-memory normalized mach-o to in-memory Atoms.
|
|
|
|
///
|
|
|
|
/// +------------+
|
|
|
|
/// | normalized |
|
|
|
|
/// +------------+
|
|
|
|
/// |
|
|
|
|
/// |
|
|
|
|
/// v
|
|
|
|
/// +-------+
|
|
|
|
/// | Atoms |
|
|
|
|
/// +-------+
|
|
|
|
|
|
|
|
#include "MachONormalizedFile.h"
|
2014-07-17 03:49:02 +08:00
|
|
|
#include "ArchHandler.h"
|
2014-01-04 07:12:02 +08:00
|
|
|
#include "Atoms.h"
|
2014-07-17 03:49:02 +08:00
|
|
|
#include "File.h"
|
|
|
|
#include "MachONormalizedFileBinaryUtils.h"
|
2014-05-28 03:35:41 +08:00
|
|
|
#include "lld/Core/Error.h"
|
2014-01-04 07:12:02 +08:00
|
|
|
#include "lld/Core/LLVM.h"
|
2014-06-28 02:25:01 +08:00
|
|
|
#include "llvm/Support/Format.h"
|
2014-10-18 13:33:55 +08:00
|
|
|
#include "llvm/Support/MachO.h"
|
2014-01-04 07:12:02 +08:00
|
|
|
|
|
|
|
using namespace llvm::MachO;
|
2014-06-04 07:36:50 +08:00
|
|
|
using namespace lld::mach_o::normalized;
|
2014-01-04 07:12:02 +08:00
|
|
|
|
|
|
|
namespace lld {
|
|
|
|
namespace mach_o {
|
|
|
|
|
2014-05-30 07:07:20 +08:00
|
|
|
|
2014-06-04 07:36:50 +08:00
|
|
|
namespace { // anonymous
|
|
|
|
|
|
|
|
|
2014-06-10 09:50:00 +08:00
|
|
|
#define ENTRY(seg, sect, type, atomType) \
|
|
|
|
{seg, sect, type, DefinedAtom::atomType }
|
|
|
|
|
|
|
|
struct MachORelocatableSectionToAtomType {
|
|
|
|
StringRef segmentName;
|
|
|
|
StringRef sectionName;
|
|
|
|
SectionType sectionType;
|
|
|
|
DefinedAtom::ContentType atomType;
|
|
|
|
};
|
2014-06-04 07:36:50 +08:00
|
|
|
|
2014-06-10 09:50:00 +08:00
|
|
|
const MachORelocatableSectionToAtomType sectsToAtomType[] = {
|
|
|
|
ENTRY("__TEXT", "__text", S_REGULAR, typeCode),
|
2014-06-11 08:24:16 +08:00
|
|
|
ENTRY("__TEXT", "__text", S_REGULAR, typeResolver),
|
2014-06-10 09:50:00 +08:00
|
|
|
ENTRY("__TEXT", "__cstring", S_CSTRING_LITERALS, typeCString),
|
|
|
|
ENTRY("", "", S_CSTRING_LITERALS, typeCString),
|
|
|
|
ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String),
|
|
|
|
ENTRY("__TEXT", "__const", S_REGULAR, typeConstant),
|
2014-06-28 02:25:01 +08:00
|
|
|
ENTRY("__TEXT", "__const_coal", S_COALESCED, typeConstant),
|
2014-06-10 09:50:00 +08:00
|
|
|
ENTRY("__TEXT", "__eh_frame", S_COALESCED, typeCFI),
|
2014-07-22 06:06:57 +08:00
|
|
|
ENTRY("__TEXT", "__eh_frame", S_REGULAR, typeCFI),
|
2014-06-10 09:50:00 +08:00
|
|
|
ENTRY("__TEXT", "__literal4", S_4BYTE_LITERALS, typeLiteral4),
|
|
|
|
ENTRY("__TEXT", "__literal8", S_8BYTE_LITERALS, typeLiteral8),
|
|
|
|
ENTRY("__TEXT", "__literal16", S_16BYTE_LITERALS, typeLiteral16),
|
|
|
|
ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR, typeLSDA),
|
|
|
|
ENTRY("__DATA", "__data", S_REGULAR, typeData),
|
2014-06-28 02:25:01 +08:00
|
|
|
ENTRY("__DATA", "__datacoal_nt", S_COALESCED, typeData),
|
2014-06-10 09:50:00 +08:00
|
|
|
ENTRY("__DATA", "__const", S_REGULAR, typeConstData),
|
|
|
|
ENTRY("__DATA", "__cfstring", S_REGULAR, typeCFString),
|
|
|
|
ENTRY("__DATA", "__mod_init_func", S_MOD_INIT_FUNC_POINTERS,
|
|
|
|
typeInitializerPtr),
|
|
|
|
ENTRY("__DATA", "__mod_term_func", S_MOD_TERM_FUNC_POINTERS,
|
|
|
|
typeTerminatorPtr),
|
|
|
|
ENTRY("__DATA", "___got", S_NON_LAZY_SYMBOL_POINTERS,
|
|
|
|
typeGOT),
|
|
|
|
ENTRY("__DATA", "___bss", S_ZEROFILL, typeZeroFill),
|
|
|
|
ENTRY("", "", S_NON_LAZY_SYMBOL_POINTERS,
|
|
|
|
typeGOT),
|
2014-11-06 09:09:13 +08:00
|
|
|
ENTRY("__DATA", "__interposing", S_INTERPOSING, typeInterposingTuples),
|
|
|
|
ENTRY("", "", S_INTERPOSING, typeInterposingTuples),
|
2014-06-10 09:50:00 +08:00
|
|
|
ENTRY("__LD", "__compact_unwind", S_REGULAR,
|
2014-06-04 07:36:50 +08:00
|
|
|
typeCompactUnwindInfo),
|
2014-06-10 09:50:00 +08:00
|
|
|
ENTRY("", "", S_REGULAR, typeUnknown)
|
|
|
|
};
|
|
|
|
#undef ENTRY
|
2014-06-04 07:36:50 +08:00
|
|
|
|
2014-06-10 09:50:00 +08:00
|
|
|
|
|
|
|
/// Figures out ContentType of a mach-o section.
|
2014-10-03 01:27:20 +08:00
|
|
|
DefinedAtom::ContentType atomTypeFromSection(const Section §ion,
|
|
|
|
bool &customSectionName) {
|
2014-06-04 07:36:50 +08:00
|
|
|
// First look for match of name and type. Empty names in table are wildcards.
|
2014-10-03 01:27:20 +08:00
|
|
|
customSectionName = false;
|
2014-06-04 07:36:50 +08:00
|
|
|
for (const MachORelocatableSectionToAtomType *p = sectsToAtomType ;
|
|
|
|
p->atomType != DefinedAtom::typeUnknown; ++p) {
|
|
|
|
if (p->sectionType != section.type)
|
2014-01-08 10:52:58 +08:00
|
|
|
continue;
|
2014-06-04 07:36:50 +08:00
|
|
|
if (!p->segmentName.equals(section.segmentName) && !p->segmentName.empty())
|
2014-01-14 06:28:02 +08:00
|
|
|
continue;
|
2014-06-04 07:36:50 +08:00
|
|
|
if (!p->sectionName.equals(section.sectionName) && !p->sectionName.empty())
|
2014-01-14 06:28:02 +08:00
|
|
|
continue;
|
2014-10-03 01:27:20 +08:00
|
|
|
customSectionName = p->segmentName.empty() && p->sectionName.empty();
|
2014-06-04 07:36:50 +08:00
|
|
|
return p->atomType;
|
2014-01-14 06:28:02 +08:00
|
|
|
}
|
2014-06-04 07:36:50 +08:00
|
|
|
// Look for code denoted by section attributes
|
|
|
|
if (section.attributes & S_ATTR_PURE_INSTRUCTIONS)
|
|
|
|
return DefinedAtom::typeCode;
|
|
|
|
|
|
|
|
return DefinedAtom::typeUnknown;
|
2014-01-08 10:52:58 +08:00
|
|
|
}
|
|
|
|
|
2014-06-04 07:36:50 +08:00
|
|
|
enum AtomizeModel {
|
|
|
|
atomizeAtSymbols,
|
|
|
|
atomizeFixedSize,
|
|
|
|
atomizePointerSize,
|
|
|
|
atomizeUTF8,
|
|
|
|
atomizeUTF16,
|
|
|
|
atomizeCFI,
|
2014-06-28 02:25:01 +08:00
|
|
|
atomizeCU,
|
|
|
|
atomizeCFString
|
2014-06-04 07:36:50 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Returns info on how to atomize a section of the specified ContentType.
|
|
|
|
void sectionParseInfo(DefinedAtom::ContentType atomType,
|
|
|
|
unsigned int &sizeMultiple,
|
|
|
|
DefinedAtom::Scope &scope,
|
|
|
|
DefinedAtom::Merge &merge,
|
|
|
|
AtomizeModel &atomizeModel) {
|
|
|
|
struct ParseInfo {
|
|
|
|
DefinedAtom::ContentType atomType;
|
|
|
|
unsigned int sizeMultiple;
|
|
|
|
DefinedAtom::Scope scope;
|
|
|
|
DefinedAtom::Merge merge;
|
|
|
|
AtomizeModel atomizeModel;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define ENTRY(type, size, scope, merge, model) \
|
|
|
|
{DefinedAtom::type, size, DefinedAtom::scope, DefinedAtom::merge, model }
|
|
|
|
|
|
|
|
static const ParseInfo parseInfo[] = {
|
|
|
|
ENTRY(typeCode, 1, scopeGlobal, mergeNo,
|
|
|
|
atomizeAtSymbols),
|
|
|
|
ENTRY(typeData, 1, scopeGlobal, mergeNo,
|
|
|
|
atomizeAtSymbols),
|
|
|
|
ENTRY(typeConstData, 1, scopeGlobal, mergeNo,
|
|
|
|
atomizeAtSymbols),
|
|
|
|
ENTRY(typeZeroFill, 1, scopeGlobal, mergeNo,
|
|
|
|
atomizeAtSymbols),
|
|
|
|
ENTRY(typeConstant, 1, scopeGlobal, mergeNo,
|
|
|
|
atomizeAtSymbols),
|
|
|
|
ENTRY(typeCString, 1, scopeLinkageUnit, mergeByContent,
|
|
|
|
atomizeUTF8),
|
|
|
|
ENTRY(typeUTF16String, 1, scopeLinkageUnit, mergeByContent,
|
|
|
|
atomizeUTF16),
|
2014-07-22 06:06:57 +08:00
|
|
|
ENTRY(typeCFI, 4, scopeTranslationUnit, mergeNo,
|
2014-06-04 07:36:50 +08:00
|
|
|
atomizeCFI),
|
|
|
|
ENTRY(typeLiteral4, 4, scopeLinkageUnit, mergeByContent,
|
|
|
|
atomizeFixedSize),
|
|
|
|
ENTRY(typeLiteral8, 8, scopeLinkageUnit, mergeByContent,
|
|
|
|
atomizeFixedSize),
|
|
|
|
ENTRY(typeLiteral16, 16, scopeLinkageUnit, mergeByContent,
|
|
|
|
atomizeFixedSize),
|
2014-06-28 02:25:01 +08:00
|
|
|
ENTRY(typeCFString, 4, scopeLinkageUnit, mergeByContent,
|
|
|
|
atomizeCFString),
|
2014-06-04 07:36:50 +08:00
|
|
|
ENTRY(typeInitializerPtr, 4, scopeTranslationUnit, mergeNo,
|
|
|
|
atomizePointerSize),
|
|
|
|
ENTRY(typeTerminatorPtr, 4, scopeTranslationUnit, mergeNo,
|
|
|
|
atomizePointerSize),
|
|
|
|
ENTRY(typeCompactUnwindInfo, 4, scopeTranslationUnit, mergeNo,
|
|
|
|
atomizeCU),
|
|
|
|
ENTRY(typeGOT, 4, scopeLinkageUnit, mergeByContent,
|
|
|
|
atomizePointerSize),
|
|
|
|
ENTRY(typeUnknown, 1, scopeGlobal, mergeNo,
|
|
|
|
atomizeAtSymbols)
|
|
|
|
};
|
|
|
|
#undef ENTRY
|
|
|
|
const int tableLen = sizeof(parseInfo) / sizeof(ParseInfo);
|
|
|
|
for (int i=0; i < tableLen; ++i) {
|
|
|
|
if (parseInfo[i].atomType == atomType) {
|
|
|
|
sizeMultiple = parseInfo[i].sizeMultiple;
|
|
|
|
scope = parseInfo[i].scope;
|
|
|
|
merge = parseInfo[i].merge;
|
|
|
|
atomizeModel = parseInfo[i].atomizeModel;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unknown type is atomized by symbols.
|
|
|
|
sizeMultiple = 1;
|
|
|
|
scope = DefinedAtom::scopeGlobal;
|
|
|
|
merge = DefinedAtom::mergeNo;
|
|
|
|
atomizeModel = atomizeAtSymbols;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Atom::Scope atomScope(uint8_t scope) {
|
2014-01-14 06:28:02 +08:00
|
|
|
switch (scope) {
|
|
|
|
case N_EXT:
|
|
|
|
return Atom::scopeGlobal;
|
2014-06-30 17:11:38 +08:00
|
|
|
case N_PEXT:
|
2014-01-14 06:28:02 +08:00
|
|
|
case N_PEXT | N_EXT:
|
|
|
|
return Atom::scopeLinkageUnit;
|
|
|
|
case 0:
|
|
|
|
return Atom::scopeTranslationUnit;
|
|
|
|
}
|
|
|
|
llvm_unreachable("unknown scope value!");
|
|
|
|
}
|
|
|
|
|
2014-06-04 07:36:50 +08:00
|
|
|
void appendSymbolsInSection(const std::vector<Symbol> &inSymbols,
|
|
|
|
uint32_t sectionIndex,
|
|
|
|
SmallVector<const Symbol *, 64> &outSyms) {
|
|
|
|
for (const Symbol &sym : inSymbols) {
|
|
|
|
// Only look at definition symbols.
|
|
|
|
if ((sym.type & N_TYPE) != N_SECT)
|
|
|
|
continue;
|
|
|
|
if (sym.sect != sectionIndex)
|
|
|
|
continue;
|
|
|
|
outSyms.push_back(&sym);
|
2014-05-31 06:51:04 +08:00
|
|
|
}
|
2014-05-16 07:03:50 +08:00
|
|
|
}
|
|
|
|
|
2014-06-04 07:36:50 +08:00
|
|
|
void atomFromSymbol(DefinedAtom::ContentType atomType, const Section §ion,
|
2014-06-04 08:34:27 +08:00
|
|
|
MachOFile &file, uint64_t symbolAddr, StringRef symbolName,
|
2014-06-11 08:24:16 +08:00
|
|
|
uint16_t symbolDescFlags, Atom::Scope symbolScope,
|
2014-10-22 07:45:37 +08:00
|
|
|
uint64_t nextSymbolAddr, bool scatterable, bool copyRefs) {
|
2014-06-04 07:36:50 +08:00
|
|
|
// Mach-O symbol table does have size in it. Instead the size is the
|
|
|
|
// difference between this and the next symbol.
|
2014-06-04 08:34:27 +08:00
|
|
|
uint64_t size = nextSymbolAddr - symbolAddr;
|
2014-06-28 02:25:01 +08:00
|
|
|
uint64_t offset = symbolAddr - section.address;
|
2014-10-22 07:45:37 +08:00
|
|
|
bool noDeadStrip = (symbolDescFlags & N_NO_DEAD_STRIP) || !scatterable;
|
2014-05-30 04:44:21 +08:00
|
|
|
if (section.type == llvm::MachO::S_ZEROFILL) {
|
2014-08-22 06:18:30 +08:00
|
|
|
file.addZeroFillDefinedAtom(symbolName, symbolScope, offset, size,
|
|
|
|
noDeadStrip, copyRefs, §ion);
|
2014-05-16 07:03:50 +08:00
|
|
|
} else {
|
2014-06-28 02:25:01 +08:00
|
|
|
DefinedAtom::Merge merge = (symbolDescFlags & N_WEAK_DEF)
|
2014-06-04 08:34:27 +08:00
|
|
|
? DefinedAtom::mergeAsWeak : DefinedAtom::mergeNo;
|
2014-07-04 08:11:09 +08:00
|
|
|
bool thumb = (symbolDescFlags & N_ARM_THUMB_DEF);
|
2014-06-04 07:36:50 +08:00
|
|
|
if (atomType == DefinedAtom::typeUnknown) {
|
2014-05-31 06:51:04 +08:00
|
|
|
// Mach-O needs a segment and section name. Concatentate those two
|
2014-09-04 03:52:50 +08:00
|
|
|
// with a / separator (e.g. "seg/sect") to fit into the lld model
|
2014-05-31 06:51:04 +08:00
|
|
|
// of just a section name.
|
2014-06-04 07:36:50 +08:00
|
|
|
std::string segSectName = section.segmentName.str()
|
2014-05-31 06:51:04 +08:00
|
|
|
+ "/" + section.sectionName.str();
|
2014-06-04 08:34:27 +08:00
|
|
|
file.addDefinedAtomInCustomSection(symbolName, symbolScope, atomType,
|
2014-08-22 06:18:30 +08:00
|
|
|
merge, thumb, noDeadStrip, offset,
|
|
|
|
size, segSectName, true, §ion);
|
2014-05-31 06:51:04 +08:00
|
|
|
} else {
|
2014-06-28 02:25:01 +08:00
|
|
|
if ((atomType == lld::DefinedAtom::typeCode) &&
|
2014-06-11 08:24:16 +08:00
|
|
|
(symbolDescFlags & N_SYMBOL_RESOLVER)) {
|
2014-06-28 02:25:01 +08:00
|
|
|
atomType = lld::DefinedAtom::typeResolver;
|
2014-06-11 08:24:16 +08:00
|
|
|
}
|
2014-06-04 08:34:27 +08:00
|
|
|
file.addDefinedAtom(symbolName, symbolScope, atomType, merge,
|
2014-08-22 06:18:30 +08:00
|
|
|
offset, size, thumb, noDeadStrip, copyRefs, §ion);
|
2014-05-31 06:51:04 +08:00
|
|
|
}
|
2014-05-16 07:03:50 +08:00
|
|
|
}
|
2014-01-13 06:55:49 +08:00
|
|
|
}
|
|
|
|
|
2014-06-12 22:53:47 +08:00
|
|
|
std::error_code processSymboledSection(DefinedAtom::ContentType atomType,
|
|
|
|
const Section §ion,
|
|
|
|
const NormalizedFile &normalizedFile,
|
2014-10-22 07:45:37 +08:00
|
|
|
MachOFile &file, bool scatterable,
|
|
|
|
bool copyRefs) {
|
2014-06-04 07:36:50 +08:00
|
|
|
// Find section's index.
|
|
|
|
uint32_t sectIndex = 1;
|
|
|
|
for (auto § : normalizedFile.sections) {
|
|
|
|
if (§ == §ion)
|
|
|
|
break;
|
|
|
|
++sectIndex;
|
2014-05-16 04:59:23 +08:00
|
|
|
}
|
|
|
|
|
2014-06-04 07:36:50 +08:00
|
|
|
// Find all symbols in this section.
|
|
|
|
SmallVector<const Symbol *, 64> symbols;
|
|
|
|
appendSymbolsInSection(normalizedFile.globalSymbols, sectIndex, symbols);
|
|
|
|
appendSymbolsInSection(normalizedFile.localSymbols, sectIndex, symbols);
|
2014-05-30 04:44:21 +08:00
|
|
|
|
2014-06-10 07:35:37 +08:00
|
|
|
// Sort symbols.
|
2014-06-04 07:36:50 +08:00
|
|
|
std::sort(symbols.begin(), symbols.end(),
|
|
|
|
[](const Symbol *lhs, const Symbol *rhs) -> bool {
|
2014-06-28 02:25:01 +08:00
|
|
|
if (lhs == rhs)
|
|
|
|
return false;
|
2014-06-10 07:35:37 +08:00
|
|
|
// First by address.
|
2014-06-28 02:25:01 +08:00
|
|
|
uint64_t lhsAddr = lhs->value;
|
|
|
|
uint64_t rhsAddr = rhs->value;
|
|
|
|
if (lhsAddr != rhsAddr)
|
|
|
|
return lhsAddr < rhsAddr;
|
|
|
|
// If same address, one is an alias so sort by scope.
|
2014-06-10 07:35:37 +08:00
|
|
|
Atom::Scope lScope = atomScope(lhs->scope);
|
|
|
|
Atom::Scope rScope = atomScope(rhs->scope);
|
|
|
|
if (lScope != rScope)
|
|
|
|
return lScope < rScope;
|
2014-09-10 07:52:59 +08:00
|
|
|
// If same address and scope, see if one might be better as
|
|
|
|
// the alias.
|
|
|
|
bool lPrivate = (lhs->name.front() == 'l');
|
|
|
|
bool rPrivate = (rhs->name.front() == 'l');
|
|
|
|
if (lPrivate != rPrivate)
|
|
|
|
return lPrivate;
|
2014-06-25 23:12:55 +08:00
|
|
|
// If same address and scope, sort by name.
|
|
|
|
return lhs->name < rhs->name;
|
2014-06-04 07:36:50 +08:00
|
|
|
});
|
2014-05-30 04:44:21 +08:00
|
|
|
|
2014-06-04 07:36:50 +08:00
|
|
|
// Debug logging of symbols.
|
|
|
|
//for (const Symbol *sym : symbols)
|
2014-06-28 02:25:01 +08:00
|
|
|
// llvm::errs() << " sym: "
|
|
|
|
// << llvm::format("0x%08llx ", (uint64_t)sym->value)
|
|
|
|
// << ", " << sym->name << "\n";
|
2014-05-30 07:07:20 +08:00
|
|
|
|
2014-06-04 07:36:50 +08:00
|
|
|
// If section has no symbols and no content, there are no atoms.
|
|
|
|
if (symbols.empty() && section.content.empty())
|
2014-06-12 22:53:47 +08:00
|
|
|
return std::error_code();
|
2014-06-04 07:36:50 +08:00
|
|
|
|
2014-06-28 02:25:01 +08:00
|
|
|
if (symbols.empty()) {
|
|
|
|
// Section has no symbols, put all content in one anoymous atom.
|
|
|
|
atomFromSymbol(atomType, section, file, section.address, StringRef(),
|
|
|
|
0, Atom::scopeTranslationUnit,
|
2014-10-22 07:45:37 +08:00
|
|
|
section.address + section.content.size(),
|
|
|
|
scatterable, copyRefs);
|
2014-06-28 02:25:01 +08:00
|
|
|
}
|
|
|
|
else if (symbols.front()->value != section.address) {
|
2014-06-04 07:36:50 +08:00
|
|
|
// Section has anonymous content before first symbol.
|
2014-06-28 02:25:01 +08:00
|
|
|
atomFromSymbol(atomType, section, file, section.address, StringRef(),
|
|
|
|
0, Atom::scopeTranslationUnit, symbols.front()->value,
|
2014-10-22 07:45:37 +08:00
|
|
|
scatterable, copyRefs);
|
2014-05-30 07:07:20 +08:00
|
|
|
}
|
|
|
|
|
2014-06-04 07:36:50 +08:00
|
|
|
const Symbol *lastSym = nullptr;
|
|
|
|
for (const Symbol *sym : symbols) {
|
|
|
|
if (lastSym != nullptr) {
|
2014-09-10 07:52:59 +08:00
|
|
|
// Ignore any assembler added "ltmpNNN" symbol at start of section
|
|
|
|
// if there is another symbol at the start.
|
|
|
|
if ((lastSym->value != sym->value)
|
|
|
|
|| lastSym->value != section.address
|
|
|
|
|| !lastSym->name.startswith("ltmp")) {
|
|
|
|
atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name,
|
|
|
|
lastSym->desc, atomScope(lastSym->scope), sym->value,
|
2014-10-22 07:45:37 +08:00
|
|
|
scatterable, copyRefs);
|
2014-09-10 07:52:59 +08:00
|
|
|
}
|
2014-06-04 07:36:50 +08:00
|
|
|
}
|
|
|
|
lastSym = sym;
|
2014-05-30 07:50:48 +08:00
|
|
|
}
|
2014-06-04 07:36:50 +08:00
|
|
|
if (lastSym != nullptr) {
|
2014-06-04 08:34:27 +08:00
|
|
|
atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name,
|
2014-06-11 08:24:16 +08:00
|
|
|
lastSym->desc, atomScope(lastSym->scope),
|
2014-10-22 07:45:37 +08:00
|
|
|
section.address + section.content.size(),
|
|
|
|
scatterable, copyRefs);
|
2014-05-30 07:50:48 +08:00
|
|
|
}
|
2014-10-22 07:45:37 +08:00
|
|
|
|
|
|
|
// If object built without .subsections_via_symbols, add reference chain.
|
|
|
|
if (!scatterable) {
|
|
|
|
MachODefinedAtom *prevAtom = nullptr;
|
|
|
|
file.eachAtomInSection(section,
|
|
|
|
[&](MachODefinedAtom *atom, uint64_t offset)->void {
|
|
|
|
if (prevAtom)
|
|
|
|
prevAtom->addReference(0, Reference::kindLayoutAfter, atom, 0,
|
|
|
|
Reference::KindArch::all,
|
|
|
|
Reference::KindNamespace::all);
|
|
|
|
prevAtom = atom;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-06-12 22:53:47 +08:00
|
|
|
return std::error_code();
|
2014-05-30 07:50:48 +08:00
|
|
|
}
|
|
|
|
|
2014-06-12 22:53:47 +08:00
|
|
|
std::error_code processSection(DefinedAtom::ContentType atomType,
|
|
|
|
const Section §ion,
|
2014-10-03 01:27:20 +08:00
|
|
|
bool customSectionName,
|
2014-06-12 22:53:47 +08:00
|
|
|
const NormalizedFile &normalizedFile,
|
2014-10-22 07:45:37 +08:00
|
|
|
MachOFile &file, bool scatterable,
|
|
|
|
bool copyRefs) {
|
2014-06-04 07:36:50 +08:00
|
|
|
const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
|
2014-10-28 06:48:35 +08:00
|
|
|
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
|
2014-06-04 07:36:50 +08:00
|
|
|
|
|
|
|
// Get info on how to atomize section.
|
|
|
|
unsigned int sizeMultiple;
|
|
|
|
DefinedAtom::Scope scope;
|
|
|
|
DefinedAtom::Merge merge;
|
|
|
|
AtomizeModel atomizeModel;
|
|
|
|
sectionParseInfo(atomType, sizeMultiple, scope, merge, atomizeModel);
|
|
|
|
|
|
|
|
// Validate section size.
|
|
|
|
if ((section.content.size() % sizeMultiple) != 0)
|
|
|
|
return make_dynamic_error_code(Twine("Section ") + section.segmentName
|
2014-05-28 07:20:52 +08:00
|
|
|
+ "/" + section.sectionName
|
2014-06-04 07:36:50 +08:00
|
|
|
+ " has size ("
|
2014-05-28 07:20:52 +08:00
|
|
|
+ Twine(section.content.size())
|
2014-06-04 07:36:50 +08:00
|
|
|
+ ") which is not a multiple of "
|
|
|
|
+ Twine(sizeMultiple) );
|
|
|
|
|
|
|
|
if (atomizeModel == atomizeAtSymbols) {
|
|
|
|
// Break section up into atoms each with a fixed size.
|
|
|
|
return processSymboledSection(atomType, section, normalizedFile, file,
|
2014-10-22 07:45:37 +08:00
|
|
|
scatterable, copyRefs);
|
2014-06-04 07:36:50 +08:00
|
|
|
} else {
|
|
|
|
unsigned int size;
|
|
|
|
for (unsigned int offset = 0, e = section.content.size(); offset != e;) {
|
|
|
|
switch (atomizeModel) {
|
|
|
|
case atomizeFixedSize:
|
|
|
|
// Break section up into atoms each with a fixed size.
|
|
|
|
size = sizeMultiple;
|
|
|
|
break;
|
|
|
|
case atomizePointerSize:
|
|
|
|
// Break section up into atoms each the size of a pointer.
|
2014-06-28 02:25:01 +08:00
|
|
|
size = is64 ? 8 : 4;
|
2014-06-04 07:36:50 +08:00
|
|
|
break;
|
|
|
|
case atomizeUTF8:
|
|
|
|
// Break section up into zero terminated c-strings.
|
|
|
|
size = 0;
|
2014-06-25 19:21:51 +08:00
|
|
|
for (unsigned int i = offset; i < e; ++i) {
|
2014-06-04 07:36:50 +08:00
|
|
|
if (section.content[i] == 0) {
|
2014-06-25 19:21:51 +08:00
|
|
|
size = i + 1 - offset;
|
2014-06-04 07:36:50 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case atomizeUTF16:
|
|
|
|
// Break section up into zero terminated UTF16 strings.
|
|
|
|
size = 0;
|
2014-06-25 19:21:51 +08:00
|
|
|
for (unsigned int i = offset; i < e; i += 2) {
|
|
|
|
if ((section.content[i] == 0) && (section.content[i + 1] == 0)) {
|
|
|
|
size = i + 2 - offset;
|
2014-06-04 07:36:50 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case atomizeCFI:
|
|
|
|
// Break section up into dwarf unwind CFIs (FDE or CIE).
|
2014-10-28 06:48:35 +08:00
|
|
|
size = read32(§ion.content[offset], isBig) + 4;
|
2014-06-04 07:36:50 +08:00
|
|
|
if (offset+size > section.content.size()) {
|
|
|
|
return make_dynamic_error_code(Twine(Twine("Section ")
|
|
|
|
+ section.segmentName
|
|
|
|
+ "/" + section.sectionName
|
|
|
|
+ " is malformed. Size of CFI "
|
|
|
|
"starting at offset ("
|
|
|
|
+ Twine(offset)
|
|
|
|
+ ") is past end of section."));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case atomizeCU:
|
|
|
|
// Break section up into compact unwind entries.
|
|
|
|
size = is64 ? 32 : 20;
|
|
|
|
break;
|
2014-06-28 02:25:01 +08:00
|
|
|
case atomizeCFString:
|
2014-07-01 04:44:47 +08:00
|
|
|
// Break section up into NS/CFString objects.
|
2014-06-28 02:25:01 +08:00
|
|
|
size = is64 ? 32 : 16;
|
|
|
|
break;
|
2014-06-04 07:36:50 +08:00
|
|
|
case atomizeAtSymbols:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (size == 0) {
|
|
|
|
return make_dynamic_error_code(Twine("Section ") + section.segmentName
|
2014-05-28 09:16:35 +08:00
|
|
|
+ "/" + section.sectionName
|
2014-06-04 07:36:50 +08:00
|
|
|
+ " is malformed. The last atom is "
|
|
|
|
"not zero terminated.");
|
2014-05-22 09:42:06 +08:00
|
|
|
}
|
2014-10-03 01:27:20 +08:00
|
|
|
if (customSectionName) {
|
|
|
|
// Mach-O needs a segment and section name. Concatentate those two
|
|
|
|
// with a / separator (e.g. "seg/sect") to fit into the lld model
|
|
|
|
// of just a section name.
|
|
|
|
std::string segSectName = section.segmentName.str()
|
|
|
|
+ "/" + section.sectionName.str();
|
|
|
|
file.addDefinedAtomInCustomSection(StringRef(), scope, atomType,
|
|
|
|
merge, false, false, offset,
|
|
|
|
size, segSectName, true, §ion);
|
|
|
|
} else {
|
|
|
|
file.addDefinedAtom(StringRef(), scope, atomType, merge, offset, size,
|
|
|
|
false, false, copyRefs, §ion);
|
|
|
|
}
|
2014-06-04 07:36:50 +08:00
|
|
|
offset += size;
|
2014-05-22 09:42:06 +08:00
|
|
|
}
|
|
|
|
}
|
2014-06-12 22:53:47 +08:00
|
|
|
return std::error_code();
|
2014-05-22 09:42:06 +08:00
|
|
|
}
|
2014-05-16 04:59:23 +08:00
|
|
|
|
2014-07-25 07:06:56 +08:00
|
|
|
const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile,
|
|
|
|
uint64_t address) {
|
|
|
|
for (const Section &s : normalizedFile.sections) {
|
|
|
|
uint64_t sAddr = s.address;
|
|
|
|
if ((sAddr <= address) && (address < sAddr+s.content.size())) {
|
|
|
|
return &s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-10-16 02:19:31 +08:00
|
|
|
const MachODefinedAtom *
|
|
|
|
findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file,
|
|
|
|
uint64_t addr, Reference::Addend *addend) {
|
|
|
|
const Section *sect = nullptr;
|
|
|
|
sect = findSectionCoveringAddress(normalizedFile, addr);
|
|
|
|
if (!sect)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
uint32_t offsetInTarget;
|
|
|
|
uint64_t offsetInSect = addr - sect->address;
|
|
|
|
auto atom =
|
|
|
|
file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
|
|
|
|
*addend = offsetInTarget;
|
|
|
|
return atom;
|
|
|
|
}
|
|
|
|
|
2014-06-28 02:25:01 +08:00
|
|
|
// Walks all relocations for a section in a normalized .o file and
|
|
|
|
// creates corresponding lld::Reference objects.
|
|
|
|
std::error_code convertRelocs(const Section §ion,
|
|
|
|
const NormalizedFile &normalizedFile,
|
2014-10-22 07:45:37 +08:00
|
|
|
bool scatterable,
|
2014-06-28 02:25:01 +08:00
|
|
|
MachOFile &file,
|
2014-07-17 03:49:02 +08:00
|
|
|
ArchHandler &handler) {
|
|
|
|
// Utility function for ArchHandler to find atom by its address.
|
2014-06-28 02:25:01 +08:00
|
|
|
auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr,
|
|
|
|
const lld::Atom **atom, Reference::Addend *addend)
|
|
|
|
-> std::error_code {
|
|
|
|
if (sectIndex > normalizedFile.sections.size())
|
|
|
|
return make_dynamic_error_code(Twine("out of range section "
|
|
|
|
"index (") + Twine(sectIndex) + ")");
|
2014-07-03 07:52:22 +08:00
|
|
|
const Section *sect = nullptr;
|
|
|
|
if (sectIndex == 0) {
|
2014-07-25 07:06:56 +08:00
|
|
|
sect = findSectionCoveringAddress(normalizedFile, addr);
|
|
|
|
if (!sect)
|
2014-07-03 07:52:22 +08:00
|
|
|
return make_dynamic_error_code(Twine("address (" + Twine(addr)
|
2014-07-25 07:06:56 +08:00
|
|
|
+ ") is not in any section"));
|
2014-07-03 07:52:22 +08:00
|
|
|
} else {
|
|
|
|
sect = &normalizedFile.sections[sectIndex-1];
|
|
|
|
}
|
2014-06-28 02:25:01 +08:00
|
|
|
uint32_t offsetInTarget;
|
2014-07-03 07:52:22 +08:00
|
|
|
uint64_t offsetInSect = addr - sect->address;
|
|
|
|
*atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
|
2014-06-28 02:25:01 +08:00
|
|
|
*addend = offsetInTarget;
|
|
|
|
return std::error_code();
|
|
|
|
};
|
|
|
|
|
2014-07-17 03:49:02 +08:00
|
|
|
// Utility function for ArchHandler to find atom by its symbol index.
|
2014-06-28 02:25:01 +08:00
|
|
|
auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result)
|
|
|
|
-> std::error_code {
|
|
|
|
// Find symbol from index.
|
|
|
|
const Symbol *sym = nullptr;
|
|
|
|
uint32_t numLocal = normalizedFile.localSymbols.size();
|
|
|
|
uint32_t numGlobal = normalizedFile.globalSymbols.size();
|
|
|
|
uint32_t numUndef = normalizedFile.undefinedSymbols.size();
|
|
|
|
if (symbolIndex < numLocal) {
|
|
|
|
sym = &normalizedFile.localSymbols[symbolIndex];
|
|
|
|
} else if (symbolIndex < numLocal+numGlobal) {
|
|
|
|
sym = &normalizedFile.globalSymbols[symbolIndex-numLocal];
|
|
|
|
} else if (symbolIndex < numLocal+numGlobal+numUndef) {
|
|
|
|
sym = &normalizedFile.undefinedSymbols[symbolIndex-numLocal-numGlobal];
|
|
|
|
} else {
|
|
|
|
return make_dynamic_error_code(Twine("symbol index (")
|
|
|
|
+ Twine(symbolIndex) + ") out of range");
|
|
|
|
}
|
|
|
|
// Find atom from symbol.
|
|
|
|
if ((sym->type & N_TYPE) == N_SECT) {
|
|
|
|
if (sym->sect > normalizedFile.sections.size())
|
|
|
|
return make_dynamic_error_code(Twine("symbol section index (")
|
|
|
|
+ Twine(sym->sect) + ") out of range ");
|
|
|
|
const Section &symSection = normalizedFile.sections[sym->sect-1];
|
|
|
|
uint64_t targetOffsetInSect = sym->value - symSection.address;
|
|
|
|
MachODefinedAtom *target = file.findAtomCoveringAddress(symSection,
|
|
|
|
targetOffsetInSect);
|
|
|
|
if (target) {
|
|
|
|
*result = target;
|
|
|
|
return std::error_code();
|
|
|
|
}
|
|
|
|
return make_dynamic_error_code(Twine("no atom found for defined symbol"));
|
|
|
|
} else if ((sym->type & N_TYPE) == N_UNDF) {
|
|
|
|
const lld::Atom *target = file.findUndefAtom(sym->name);
|
|
|
|
if (target) {
|
|
|
|
*result = target;
|
|
|
|
return std::error_code();
|
|
|
|
}
|
|
|
|
return make_dynamic_error_code(Twine("no undefined atom found for sym"));
|
|
|
|
} else {
|
|
|
|
// Search undefs
|
|
|
|
return make_dynamic_error_code(Twine("no atom found for symbol"));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-10-28 06:48:35 +08:00
|
|
|
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
|
2014-06-28 02:25:01 +08:00
|
|
|
// Use old-school iterator so that paired relocations can be grouped.
|
|
|
|
for (auto it=section.relocations.begin(), e=section.relocations.end();
|
|
|
|
it != e; ++it) {
|
|
|
|
const Relocation &reloc = *it;
|
|
|
|
// Find atom this relocation is in.
|
|
|
|
if (reloc.offset > section.content.size())
|
|
|
|
return make_dynamic_error_code(Twine("r_address (") + Twine(reloc.offset)
|
|
|
|
+ ") is larger than section size ("
|
|
|
|
+ Twine(section.content.size()) + ")");
|
|
|
|
uint32_t offsetInAtom;
|
|
|
|
MachODefinedAtom *inAtom = file.findAtomCoveringAddress(section,
|
|
|
|
reloc.offset,
|
|
|
|
&offsetInAtom);
|
2014-07-01 04:44:47 +08:00
|
|
|
assert(inAtom && "r_address in range, should have found atom");
|
2014-06-28 02:25:01 +08:00
|
|
|
uint64_t fixupAddress = section.address + reloc.offset;
|
|
|
|
|
|
|
|
const lld::Atom *target = nullptr;
|
|
|
|
Reference::Addend addend = 0;
|
|
|
|
Reference::KindValue kind;
|
|
|
|
std::error_code relocErr;
|
|
|
|
if (handler.isPairedReloc(reloc)) {
|
|
|
|
// Handle paired relocations together.
|
2014-10-28 06:48:35 +08:00
|
|
|
relocErr = handler.getPairReferenceInfo(
|
|
|
|
reloc, *++it, inAtom, offsetInAtom, fixupAddress, isBig, scatterable,
|
|
|
|
atomByAddr, atomBySymbol, &kind, &target, &addend);
|
2014-06-28 02:25:01 +08:00
|
|
|
}
|
|
|
|
else {
|
2014-07-17 03:49:02 +08:00
|
|
|
// Use ArchHandler to convert relocation record into information
|
2014-06-28 02:25:01 +08:00
|
|
|
// needed to instantiate an lld::Reference object.
|
2014-10-28 06:48:35 +08:00
|
|
|
relocErr = handler.getReferenceInfo(
|
|
|
|
reloc, inAtom, offsetInAtom, fixupAddress, isBig, atomByAddr,
|
|
|
|
atomBySymbol, &kind, &target, &addend);
|
2014-06-28 02:25:01 +08:00
|
|
|
}
|
|
|
|
if (relocErr) {
|
|
|
|
return make_dynamic_error_code(
|
|
|
|
Twine("bad relocation (") + relocErr.message()
|
|
|
|
+ ") in section "
|
|
|
|
+ section.segmentName + "/" + section.sectionName
|
|
|
|
+ " (r_address=" + Twine::utohexstr(reloc.offset)
|
|
|
|
+ ", r_type=" + Twine(reloc.type)
|
|
|
|
+ ", r_extern=" + Twine(reloc.isExtern)
|
2014-07-03 07:52:22 +08:00
|
|
|
+ ", r_length=" + Twine((int)reloc.length)
|
2014-06-28 02:25:01 +08:00
|
|
|
+ ", r_pcrel=" + Twine(reloc.pcRel)
|
|
|
|
+ (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
|
|
|
|
: (Twine(", r_scattered=1, r_value=")
|
|
|
|
+ Twine(reloc.value)))
|
|
|
|
+ ")" );
|
|
|
|
} else {
|
|
|
|
// Instantiate an lld::Reference object and add to its atom.
|
2014-07-17 03:49:02 +08:00
|
|
|
inAtom->addReference(offsetInAtom, kind, target, addend,
|
|
|
|
handler.kindArch());
|
2014-06-28 02:25:01 +08:00
|
|
|
}
|
|
|
|
}
|
2014-07-23 08:51:37 +08:00
|
|
|
|
2014-06-28 02:25:01 +08:00
|
|
|
return std::error_code();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDebugInfoSection(const Section §ion) {
|
|
|
|
if ((section.attributes & S_ATTR_DEBUG) == 0)
|
|
|
|
return false;
|
|
|
|
return section.segmentName.equals("__DWARF");
|
|
|
|
}
|
|
|
|
|
2014-10-28 06:48:35 +08:00
|
|
|
static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) {
|
2014-10-16 02:19:31 +08:00
|
|
|
if (is64)
|
2014-10-28 06:48:35 +08:00
|
|
|
return read64(addr, isBig);
|
2014-10-16 02:19:31 +08:00
|
|
|
|
2014-10-28 06:48:35 +08:00
|
|
|
int32_t res = read32(addr, isBig);
|
2014-10-16 02:19:31 +08:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
|
|
|
|
MachOFile &file,
|
|
|
|
mach_o::ArchHandler &handler) {
|
2014-10-28 06:48:35 +08:00
|
|
|
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
|
2014-10-16 02:19:31 +08:00
|
|
|
const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
|
|
|
|
|
|
|
|
const Section *ehFrameSection = nullptr;
|
|
|
|
for (auto §ion : normalizedFile.sections)
|
|
|
|
if (section.segmentName == "__TEXT" &&
|
|
|
|
section.sectionName == "__eh_frame") {
|
|
|
|
ehFrameSection = §ion;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No __eh_frame so nothing to do.
|
|
|
|
if (!ehFrameSection)
|
|
|
|
return std::error_code();
|
|
|
|
|
|
|
|
file.eachAtomInSection(*ehFrameSection,
|
|
|
|
[&](MachODefinedAtom *atom, uint64_t offset) -> void {
|
|
|
|
assert(atom->contentType() == DefinedAtom::typeCFI);
|
|
|
|
|
2014-10-28 06:48:35 +08:00
|
|
|
if (ArchHandler::isDwarfCIE(isBig, atom))
|
2014-10-16 02:19:31 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Compiler wasn't lazy and actually told us what it meant.
|
|
|
|
if (atom->begin() != atom->end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const uint8_t *frameData = atom->rawContent().data();
|
2014-10-28 06:48:35 +08:00
|
|
|
uint32_t size = read32(frameData, isBig);
|
2014-10-16 04:26:24 +08:00
|
|
|
uint64_t cieFieldInFDE = size == 0xffffffffU
|
|
|
|
? sizeof(uint32_t) + sizeof(uint64_t)
|
|
|
|
: sizeof(uint32_t);
|
|
|
|
|
|
|
|
// Linker needs to fixup a reference from the FDE to its parent CIE (a
|
|
|
|
// 32-bit byte offset backwards in the __eh_frame section).
|
2014-10-28 06:48:35 +08:00
|
|
|
uint32_t cieDelta = read32(frameData + cieFieldInFDE, isBig);
|
2014-10-16 04:26:24 +08:00
|
|
|
uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE;
|
|
|
|
cieAddress -= cieDelta;
|
|
|
|
|
|
|
|
Reference::Addend addend;
|
|
|
|
const Atom *cie =
|
|
|
|
findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend);
|
|
|
|
atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie,
|
|
|
|
addend, handler.kindArch());
|
|
|
|
|
|
|
|
// Linker needs to fixup reference from the FDE to the function it's
|
2014-10-17 04:52:18 +08:00
|
|
|
// describing. FIXME: there are actually different ways to do this, and the
|
|
|
|
// particular method used is specified in the CIE's augmentation fields
|
|
|
|
// (hopefully)
|
2014-10-16 04:26:24 +08:00
|
|
|
uint64_t rangeFieldInFDE = cieFieldInFDE + sizeof(uint32_t);
|
2014-10-16 02:19:31 +08:00
|
|
|
|
2014-10-28 06:48:35 +08:00
|
|
|
int64_t functionFromFDE = readSPtr(is64, isBig, frameData + rangeFieldInFDE);
|
2014-10-16 02:19:31 +08:00
|
|
|
uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE;
|
|
|
|
rangeStart += functionFromFDE;
|
|
|
|
|
|
|
|
const Atom *func =
|
|
|
|
findAtomCoveringAddress(normalizedFile, file, rangeStart, &addend);
|
|
|
|
atom->addReference(rangeFieldInFDE, handler.unwindRefToFunctionKind(), func,
|
|
|
|
addend, handler.kindArch());
|
|
|
|
});
|
|
|
|
return std::error_code();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-28 02:25:01 +08:00
|
|
|
/// Converts normalized mach-o file into an lld::File and lld::Atoms.
|
2014-06-04 07:36:50 +08:00
|
|
|
ErrorOr<std::unique_ptr<lld::File>>
|
2014-01-11 09:07:43 +08:00
|
|
|
normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
|
|
|
|
bool copyRefs) {
|
2014-01-04 07:12:02 +08:00
|
|
|
std::unique_ptr<MachOFile> file(new MachOFile(path));
|
2014-10-22 07:45:37 +08:00
|
|
|
bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0);
|
|
|
|
|
2014-06-04 07:36:50 +08:00
|
|
|
// Create atoms from each section.
|
2014-05-30 07:07:20 +08:00
|
|
|
for (auto § : normalizedFile.sections) {
|
2014-06-28 02:25:01 +08:00
|
|
|
if (isDebugInfoSection(sect))
|
|
|
|
continue;
|
2014-10-03 01:27:20 +08:00
|
|
|
bool customSectionName;
|
|
|
|
DefinedAtom::ContentType atomType = atomTypeFromSection(sect,
|
|
|
|
customSectionName);
|
2014-06-12 22:53:47 +08:00
|
|
|
if (std::error_code ec =
|
2014-10-03 01:27:20 +08:00
|
|
|
processSection(atomType, sect, customSectionName, normalizedFile,
|
2014-10-22 07:45:37 +08:00
|
|
|
*file, scatterable, copyRefs))
|
2014-05-30 07:07:20 +08:00
|
|
|
return ec;
|
2014-01-14 06:28:02 +08:00
|
|
|
}
|
2014-05-30 07:07:20 +08:00
|
|
|
// Create atoms from undefined symbols.
|
2014-02-03 03:34:55 +08:00
|
|
|
for (auto &sym : normalizedFile.undefinedSymbols) {
|
2014-06-04 07:36:50 +08:00
|
|
|
// Undefinded symbols with n_value != 0 are actually tentative definitions.
|
|
|
|
if (sym.value == Hex64(0)) {
|
|
|
|
file->addUndefinedAtom(sym.name, copyRefs);
|
|
|
|
} else {
|
|
|
|
file->addTentativeDefAtom(sym.name, atomScope(sym.scope), sym.value,
|
|
|
|
DefinedAtom::Alignment(sym.desc >> 8), copyRefs);
|
|
|
|
}
|
2014-02-03 03:34:55 +08:00
|
|
|
}
|
2014-01-04 07:12:02 +08:00
|
|
|
|
2014-06-28 02:25:01 +08:00
|
|
|
// Convert mach-o relocations to References
|
2014-07-17 03:49:02 +08:00
|
|
|
std::unique_ptr<mach_o::ArchHandler> handler
|
|
|
|
= ArchHandler::create(normalizedFile.arch);
|
2014-06-28 02:25:01 +08:00
|
|
|
for (auto § : normalizedFile.sections) {
|
|
|
|
if (isDebugInfoSection(sect))
|
|
|
|
continue;
|
2014-10-22 07:45:37 +08:00
|
|
|
if (std::error_code ec = convertRelocs(sect, normalizedFile, scatterable,
|
|
|
|
*file, *handler))
|
2014-06-28 02:25:01 +08:00
|
|
|
return ec;
|
|
|
|
}
|
|
|
|
|
2014-07-23 08:51:37 +08:00
|
|
|
// Add additional arch-specific References
|
|
|
|
file->eachDefinedAtom([&](MachODefinedAtom* atom) -> void {
|
|
|
|
handler->addAdditionalReferences(*atom);
|
|
|
|
});
|
|
|
|
|
2014-10-16 02:19:31 +08:00
|
|
|
// Each __eh_frame section needs references to both __text (the function we're
|
|
|
|
// providing unwind info for) and itself (FDE -> CIE). These aren't
|
|
|
|
// represented in the relocations on some architectures, so we have to add
|
|
|
|
// them back in manually there.
|
|
|
|
if (std::error_code ec = addEHFrameReferences(normalizedFile, *file, *handler))
|
|
|
|
return ec;
|
|
|
|
|
2014-07-25 07:06:56 +08:00
|
|
|
// Process mach-o data-in-code regions array. That information is encoded in
|
|
|
|
// atoms as References at each transition point.
|
|
|
|
unsigned nextIndex = 0;
|
|
|
|
for (const DataInCode &entry : normalizedFile.dataInCode) {
|
|
|
|
++nextIndex;
|
|
|
|
const Section* s = findSectionCoveringAddress(normalizedFile, entry.offset);
|
|
|
|
if (!s) {
|
|
|
|
return make_dynamic_error_code(Twine("LC_DATA_IN_CODE address ("
|
|
|
|
+ Twine(entry.offset)
|
|
|
|
+ ") is not in any section"));
|
|
|
|
}
|
|
|
|
uint64_t offsetInSect = entry.offset - s->address;
|
|
|
|
uint32_t offsetInAtom;
|
|
|
|
MachODefinedAtom *atom = file->findAtomCoveringAddress(*s, offsetInSect,
|
|
|
|
&offsetInAtom);
|
|
|
|
if (offsetInAtom + entry.length > atom->size()) {
|
|
|
|
return make_dynamic_error_code(Twine("LC_DATA_IN_CODE entry (offset="
|
|
|
|
+ Twine(entry.offset)
|
|
|
|
+ ", length="
|
|
|
|
+ Twine(entry.length)
|
|
|
|
+ ") crosses atom boundary."));
|
|
|
|
}
|
|
|
|
// Add reference that marks start of data-in-code.
|
|
|
|
atom->addReference(offsetInAtom,
|
|
|
|
handler->dataInCodeTransitionStart(*atom), atom,
|
|
|
|
entry.kind, handler->kindArch());
|
|
|
|
|
|
|
|
// Peek at next entry, if it starts where this one ends, skip ending ref.
|
|
|
|
if (nextIndex < normalizedFile.dataInCode.size()) {
|
|
|
|
const DataInCode &nextEntry = normalizedFile.dataInCode[nextIndex];
|
|
|
|
if (nextEntry.offset == (entry.offset + entry.length))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If data goes to end of function, skip ending ref.
|
|
|
|
if ((offsetInAtom + entry.length) == atom->size())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Add reference that marks end of data-in-code.
|
|
|
|
atom->addReference(offsetInAtom+entry.length,
|
|
|
|
handler->dataInCodeTransitionEnd(*atom), atom, 0,
|
|
|
|
handler->kindArch());
|
|
|
|
}
|
|
|
|
|
2014-06-28 02:25:01 +08:00
|
|
|
// Sort references in each atom to their canonical order.
|
|
|
|
for (const DefinedAtom* defAtom : file->defined()) {
|
|
|
|
reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();
|
|
|
|
}
|
|
|
|
|
2014-01-04 07:12:02 +08:00
|
|
|
return std::unique_ptr<File>(std::move(file));
|
|
|
|
}
|
|
|
|
|
2014-06-30 17:11:38 +08:00
|
|
|
ErrorOr<std::unique_ptr<lld::File>>
|
|
|
|
normalizedDylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
|
|
|
|
bool copyRefs) {
|
2014-08-14 07:55:41 +08:00
|
|
|
// Instantiate SharedLibraryFile object.
|
2014-07-01 16:15:41 +08:00
|
|
|
std::unique_ptr<MachODylibFile> file(
|
2014-08-14 07:55:41 +08:00
|
|
|
new MachODylibFile(path, normalizedFile.installName));
|
|
|
|
// Tell MachODylibFile object about all symbols it exports.
|
2014-09-04 03:52:50 +08:00
|
|
|
if (!normalizedFile.exportInfo.empty()) {
|
|
|
|
// If exports trie exists, use it instead of traditional symbol table.
|
|
|
|
for (const Export &exp : normalizedFile.exportInfo) {
|
|
|
|
bool weakDef = (exp.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
|
|
|
|
// StringRefs from export iterator are ephemeral, so force copy.
|
|
|
|
file->addExportedSymbol(exp.name, weakDef, true);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (auto &sym : normalizedFile.globalSymbols) {
|
|
|
|
assert((sym.scope & N_EXT) && "only expect external symbols here");
|
|
|
|
bool weakDef = (sym.desc & N_WEAK_DEF);
|
|
|
|
file->addExportedSymbol(sym.name, weakDef, copyRefs);
|
|
|
|
}
|
2014-08-14 07:55:41 +08:00
|
|
|
}
|
|
|
|
// Tell MachODylibFile object about all dylibs it re-exports.
|
|
|
|
for (const DependentDylib &dep : normalizedFile.dependentDylibs) {
|
|
|
|
if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB)
|
|
|
|
file->addReExportedDylib(dep.path);
|
2014-06-30 17:11:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return std::unique_ptr<File>(std::move(file));
|
|
|
|
}
|
|
|
|
|
2014-06-04 07:36:50 +08:00
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
namespace normalized {
|
|
|
|
|
2014-06-10 09:50:00 +08:00
|
|
|
void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
|
|
|
|
StringRef &segmentName,
|
|
|
|
StringRef §ionName,
|
|
|
|
SectionType §ionType,
|
|
|
|
SectionAttr §ionAttrs) {
|
|
|
|
|
|
|
|
for (const MachORelocatableSectionToAtomType *p = sectsToAtomType ;
|
|
|
|
p->atomType != DefinedAtom::typeUnknown; ++p) {
|
|
|
|
if (p->atomType != atomType)
|
|
|
|
continue;
|
|
|
|
// Wild carded entries are ignored for reverse lookups.
|
|
|
|
if (p->segmentName.empty() || p->sectionName.empty())
|
|
|
|
continue;
|
|
|
|
segmentName = p->segmentName;
|
|
|
|
sectionName = p->sectionName;
|
|
|
|
sectionType = p->sectionType;
|
|
|
|
sectionAttrs = 0;
|
|
|
|
if (atomType == DefinedAtom::typeCode)
|
|
|
|
sectionAttrs = S_ATTR_PURE_INSTRUCTIONS;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
llvm_unreachable("content type not yet supported");
|
|
|
|
}
|
|
|
|
|
2014-01-04 07:12:02 +08:00
|
|
|
ErrorOr<std::unique_ptr<lld::File>>
|
2014-01-11 09:07:43 +08:00
|
|
|
normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
|
|
|
|
bool copyRefs) {
|
2014-01-04 07:12:02 +08:00
|
|
|
switch (normalizedFile.fileType) {
|
2014-06-30 17:11:38 +08:00
|
|
|
case MH_DYLIB:
|
2014-08-14 07:55:41 +08:00
|
|
|
case MH_DYLIB_STUB:
|
2014-06-30 17:11:38 +08:00
|
|
|
return normalizedDylibToAtoms(normalizedFile, path, copyRefs);
|
2014-01-04 07:12:02 +08:00
|
|
|
case MH_OBJECT:
|
2014-01-11 09:07:43 +08:00
|
|
|
return normalizedObjectToAtoms(normalizedFile, path, copyRefs);
|
2014-01-04 07:12:02 +08:00
|
|
|
default:
|
|
|
|
llvm_unreachable("unhandled MachO file type!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace normalized
|
|
|
|
} // namespace mach_o
|
|
|
|
} // namespace lld
|