blob: d40321bb63e04c44266feec55427d3a6a4a1fe8a [file] [log] [blame]
Joey Goulyceb16de2014-01-03 23:12:02 +00001//===- lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp --------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10///
11/// \file Converts from in-memory normalized mach-o to in-memory Atoms.
12///
13/// +------------+
14/// | normalized |
15/// +------------+
16/// |
17/// |
18/// v
19/// +-------+
20/// | Atoms |
21/// +-------+
22
23#include "MachONormalizedFile.h"
24#include "File.h"
25#include "Atoms.h"
26
27#include "lld/Core/LLVM.h"
28
29#include "llvm/Support/MachO.h"
30
31using namespace llvm::MachO;
32
33namespace lld {
34namespace mach_o {
35namespace normalized {
36
Nick Kledzik6edd7222014-01-11 01:07:43 +000037static uint64_t nextSymbolAddress(const NormalizedFile &normalizedFile,
Nick Kledzik36baa332014-01-08 02:52:58 +000038 const Symbol &symbol) {
39 uint64_t symbolAddr = symbol.value;
40 uint8_t symbolSectionIndex = symbol.sect;
41 const Section &section = normalizedFile.sections[symbolSectionIndex - 1];
42 // If no symbol after this address, use end of section address.
43 uint64_t closestAddr = section.address + section.content.size();
44 for (const Symbol &s : normalizedFile.globalSymbols) {
45 if (s.sect != symbolSectionIndex)
46 continue;
47 uint64_t sValue = s.value;
48 if (sValue <= symbolAddr)
49 continue;
50 if (sValue < closestAddr)
51 closestAddr = s.value;
52 }
Joey Goulyd2215372014-01-13 22:28:02 +000053 for (const Symbol &s : normalizedFile.localSymbols) {
54 if (s.sect != symbolSectionIndex)
55 continue;
56 uint64_t sValue = s.value;
57 if (sValue <= symbolAddr)
58 continue;
59 if (sValue < closestAddr)
60 closestAddr = s.value;
61 }
Nick Kledzik36baa332014-01-08 02:52:58 +000062 return closestAddr;
63}
64
Joey Goulyd2215372014-01-13 22:28:02 +000065static Atom::Scope atomScope(uint8_t scope) {
66 switch (scope) {
67 case N_EXT:
68 return Atom::scopeGlobal;
69 case N_PEXT | N_EXT:
70 return Atom::scopeLinkageUnit;
71 case 0:
72 return Atom::scopeTranslationUnit;
73 }
74 llvm_unreachable("unknown scope value!");
75}
76
Nick Kledzike09cfc52014-05-15 23:03:50 +000077static DefinedAtom::ContentType atomTypeFromSection(const Section &section) {
78 // FIX ME
79 return DefinedAtom::typeCode;
80}
81
Joey Gouly9c826c102014-01-12 22:55:49 +000082static void processSymbol(const NormalizedFile &normalizedFile, MachOFile &file,
83 const Symbol &sym, bool copyRefs) {
84 // Mach-O symbol table does have size in it, so need to scan ahead
85 // to find symbol with next highest address.
86 const Section &section = normalizedFile.sections[sym.sect - 1];
87 uint64_t offset = sym.value - section.address;
88 uint64_t size = nextSymbolAddress(normalizedFile, sym) - sym.value;
Nick Kledzike09cfc52014-05-15 23:03:50 +000089 if (section.type == llvm::MachO::S_ZEROFILL){
90 file.addZeroFillDefinedAtom(sym.name, atomScope(sym.scope), size, copyRefs);
91 } else {
92 ArrayRef<uint8_t> atomContent = section.content.slice(offset, size);
93 file.addDefinedAtom(sym.name, atomScope(sym.scope),
94 atomTypeFromSection(section), atomContent, copyRefs);
95 }
Joey Gouly9c826c102014-01-12 22:55:49 +000096}
97
Nick Kledzik61fdef62014-05-15 20:59:23 +000098
99static void processUndefindeSymbol(MachOFile &file, const Symbol &sym,
100 bool copyRefs) {
101 // Undefinded symbols with n_value!=0 are actually tentative definitions.
102 if (sym.value == Hex64(0)) {
103 file.addUndefinedAtom(sym.name, copyRefs);
104 } else {
105 file.addTentativeDefAtom(sym.name, atomScope(sym.scope), sym.value,
106 DefinedAtom::Alignment(sym.desc >> 8), copyRefs);
107 }
108}
109
Nick Kledzika0c13a22014-05-22 01:42:06 +0000110static void processSection(MachOFile &file, const Section &section,
111 bool copyRefs) {
112 unsigned offset = 0;
113 switch (section.type) {
114 case llvm::MachO::S_REGULAR:
115 case llvm::MachO::S_COALESCED:
116 case llvm::MachO::S_ZEROFILL:
117 // These sections are broken in to atoms based on symbols.
118 break;
119 case llvm::MachO::S_CSTRING_LITERALS:
120 for (size_t i = 0, e = section.content.size(); i != e; ++i) {
121 if (section.content[i] == 0) {
122 unsigned size = i - offset + 1;
123 ArrayRef<uint8_t> strContent = section.content.slice(offset, size);
124 file.addDefinedAtom(StringRef(), DefinedAtom::scopeLinkageUnit,
125 DefinedAtom::typeCString, strContent, copyRefs);
126 offset = i + 1;
127 }
128 }
129 break;
130 case llvm::MachO::S_4BYTE_LITERALS:
131 assert((section.content.size() % 4) == 0);
132 for (size_t i = 0, e = section.content.size(); i != e; i += 4) {
133 ArrayRef<uint8_t> byteContent = section.content.slice(offset, 4);
134 file.addDefinedAtom(StringRef(), DefinedAtom::scopeLinkageUnit,
135 DefinedAtom::typeLiteral4, byteContent, copyRefs);
136 offset += 4;
137 }
138 break;
139 case llvm::MachO::S_8BYTE_LITERALS:
140 assert((section.content.size() % 8) == 0);
141 for (size_t i = 0, e = section.content.size(); i != e; i += 8) {
142 ArrayRef<uint8_t> byteContent = section.content.slice(offset, 8);
143 file.addDefinedAtom(StringRef(), DefinedAtom::scopeLinkageUnit,
144 DefinedAtom::typeLiteral8, byteContent, copyRefs);
145 offset += 8;
146 }
147 break;
148 case llvm::MachO::S_16BYTE_LITERALS:
149 assert((section.content.size() % 16) == 0);
150 for (size_t i = 0, e = section.content.size(); i != e; i += 16) {
151 ArrayRef<uint8_t> byteContent = section.content.slice(offset, 16);
152 file.addDefinedAtom(StringRef(), DefinedAtom::scopeLinkageUnit,
153 DefinedAtom::typeLiteral16, byteContent, copyRefs);
154 offset += 16;
155 }
156 break;
157 default:
158 llvm_unreachable("mach-o section type not supported");
159 break;
160 }
161}
Nick Kledzik61fdef62014-05-15 20:59:23 +0000162
Joey Goulyceb16de2014-01-03 23:12:02 +0000163static ErrorOr<std::unique_ptr<lld::File>>
Nick Kledzik6edd7222014-01-11 01:07:43 +0000164normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
165 bool copyRefs) {
Joey Goulyceb16de2014-01-03 23:12:02 +0000166 std::unique_ptr<MachOFile> file(new MachOFile(path));
Nick Kledzika0c13a22014-05-22 01:42:06 +0000167
168 // Create atoms from global symbols.
Nick Kledzik6edd7222014-01-11 01:07:43 +0000169 for (const Symbol &sym : normalizedFile.globalSymbols) {
Joey Gouly9c826c102014-01-12 22:55:49 +0000170 processSymbol(normalizedFile, *file, sym, copyRefs);
Joey Goulyceb16de2014-01-03 23:12:02 +0000171 }
Nick Kledzika0c13a22014-05-22 01:42:06 +0000172 // Create atoms from local symbols.
Joey Goulyd2215372014-01-13 22:28:02 +0000173 for (const Symbol &sym : normalizedFile.localSymbols) {
174 processSymbol(normalizedFile, *file, sym, copyRefs);
175 }
Nick Kledzika0c13a22014-05-22 01:42:06 +0000176 // Create atoms from undefinded symbols.
Joey Goulycf466802014-02-02 19:34:55 +0000177 for (auto &sym : normalizedFile.undefinedSymbols) {
Nick Kledzik61fdef62014-05-15 20:59:23 +0000178 processUndefindeSymbol(*file, sym, copyRefs);
Joey Goulycf466802014-02-02 19:34:55 +0000179 }
Nick Kledzika0c13a22014-05-22 01:42:06 +0000180 // Create atoms from sections that don't have symbols.
181 for (auto &sect : normalizedFile.sections) {
182 processSection(*file, sect, copyRefs);
183 }
Joey Goulyceb16de2014-01-03 23:12:02 +0000184
185 return std::unique_ptr<File>(std::move(file));
186}
187
188ErrorOr<std::unique_ptr<lld::File>>
Nick Kledzik6edd7222014-01-11 01:07:43 +0000189normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
190 bool copyRefs) {
Joey Goulyceb16de2014-01-03 23:12:02 +0000191 switch (normalizedFile.fileType) {
192 case MH_OBJECT:
Nick Kledzik6edd7222014-01-11 01:07:43 +0000193 return normalizedObjectToAtoms(normalizedFile, path, copyRefs);
Joey Goulyceb16de2014-01-03 23:12:02 +0000194 default:
195 llvm_unreachable("unhandled MachO file type!");
196 }
197}
198
199} // namespace normalized
200} // namespace mach_o
201} // namespace lld