LLVM 22.0.0git
XCOFFLinkGraphBuilder.cpp
Go to the documentation of this file.
1// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2// See https://llvm.org/LICENSE.txt for license information.
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4//
5//===----------------------------------------------------------------------===//
6//
7// Generic XCOFF LinkGraph building code.
8//
9//===----------------------------------------------------------------------===//
10
12#include "llvm/ADT/STLExtras.h"
20#include "llvm/Support/Debug.h"
21#include "llvm/Support/Error.h"
22#include "llvm/Support/Format.h"
24#include <memory>
25
26using namespace llvm;
27
28#define DEBUG_TYPE "jitlink"
29
30namespace llvm {
31namespace jitlink {
32
34 const object::XCOFFObjectFile &Obj,
35 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
36 SubtargetFeatures Features,
38 : Obj(Obj),
39 G(std::make_unique<LinkGraph>(
40 std::string(Obj.getFileName()), std::move(SSP), std::move(TT),
41 std::move(Features), std::move(GetEdgeKindName))) {}
42
43#ifndef NDEBUG
45 switch (SC) {
47 return "C_FILE (File name)";
49 return "C_BINCL (Beginning of include file)";
51 return "C_EINCL (Ending of include file)";
53 return "C_GSYM (Global variable)";
55 return "C_STSYM (Statically allocated symbol)";
57 return "C_BCOMM (Beginning of common block)";
59 return "C_ECOMM (End of common block)";
61 return "C_ENTRY (Alternate entry)";
63 return "C_BSTAT (Beginning of static block)";
65 return "C_ESTAT (End of static block)";
67 return "C_GTLS (Global thread-local variable)";
69 return "C_STTLS (Static thread-local variable)";
71 return "C_DWARF (DWARF section symbol)";
73 return "C_LSYM (Automatic variable allocated on stack)";
75 return "C_PSYM (Argument to subroutine allocated on stack)";
77 return "C_RSYM (Register variable)";
79 return "C_RPSYM (Argument to function stored in register)";
81 return "C_ECOML (Local member of common block)";
83 return "C_FUN (Function or procedure)";
85 return "C_EXT (External symbol)";
87 return "C_WEAKEXT (Weak external symbol)";
89 return "C_NULL";
91 return "C_STAT (Static)";
93 return "C_BLOCK (\".bb\" or \".eb\")";
95 return "C_FCN (\".bf\" or \".ef\")";
97 return "C_HIDEXT (Un-named external symbol)";
99 return "C_INFO (Comment string in .info section)";
101 return "C_DECL (Declaration of object)";
103 return "C_AUTO (Automatic variable)";
105 return "C_REG (Register variable)";
107 return "C_EXTDEF (External definition)";
109 return "C_LABEL (Label)";
111 return "C_ULABEL (Undefined label)";
113 return "C_MOS (Member of structure)";
115 return "C_ARG (Function argument)";
117 return "C_STRTAG (Structure tag)";
119 return "C_MOU (Member of union)";
121 return "C_UNTAG (Union tag)";
123 return "C_TPDEF (Type definition)";
125 return "C_USTATIC (Undefined static)";
127 return "C_ENTAG (Enumeration tag)";
129 return "C_MOE (Member of enumeration)";
131 return "C_REGPARM (Register parameter)";
133 return "C_FIELD (Bit field)";
135 return "C_EOS (End of structure)";
137 return "C_LINE";
139 return "C_ALIAS (Duplicate tag)";
141 return "C_HIDDEN (Special storage class for external)";
143 return "C_EFCN (Physical end of function)";
145 return "C_TCSYM (Reserved)";
146 }
147 llvm_unreachable("Unknown XCOFF::StorageClass enum");
148}
149#endif
150
151Error XCOFFLinkGraphBuilder::processSections() {
152 LLVM_DEBUG(dbgs() << " Creating graph sections...\n");
153
154 UndefSection = &G->createSection("*UND*", orc::MemProt::None);
155
156 for (object::SectionRef Section : Obj.sections()) {
157 auto SectionName = Section.getName();
158 if (!SectionName)
159 return SectionName.takeError();
160
161 LLVM_DEBUG({
162 dbgs() << " section = " << *SectionName
163 << ", idx = " << Section.getIndex()
164 << ", size = " << format_hex_no_prefix(Section.getSize(), 8)
165 << ", vma = " << format_hex(Section.getAddress(), 16) << "\n";
166 });
167
168 // We can skip debug (including dawrf) and pad sections
169 if (Section.isDebugSection() || *SectionName == "pad")
170 continue;
171 LLVM_DEBUG(dbgs() << " creating graph section\n");
172
174 if (Section.isText())
175 Prot |= orc::MemProt::Exec;
176 if (Section.isData() || Section.isBSS())
177 Prot |= orc::MemProt::Write;
178
179 jitlink::Section *GraphSec = &G->createSection(*SectionName, Prot);
180 // TODO: Check for no_alloc for certain sections
181
182 assert(!SectionTable.contains(Section.getIndex()) &&
183 "Section with same index already exists");
184 SectionTable[Section.getIndex()] = {GraphSec, Section};
185 }
186
187 return Error::success();
188}
189
190static std::optional<object::XCOFFSymbolRef>
192 const object::SymbolRef &Sym) {
193 const object::XCOFFSymbolRef SymRef =
194 Obj.toSymbolRef(Sym.getRawDataRefImpl());
195 if (!SymRef.isCsectSymbol())
196 return std::nullopt;
197
198 Expected<object::XCOFFCsectAuxRef> CsectAuxEntOrErr =
199 SymRef.getXCOFFCsectAuxRef();
200 if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())
201 return std::nullopt;
202 uint32_t Idx =
203 static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());
205 DRI.p = Obj.getSymbolByIndex(Idx);
206 return object::XCOFFSymbolRef(DRI, &Obj);
207}
208
209#ifndef NDEBUG
211 const object::XCOFFObjectFile &Obj,
213 OS << " " << format_hex(cantFail(Sym.getAddress()), 16);
214 OS << " " << left_justify(cantFail(Sym.getName()), 10);
215 if (Sym.isCsectSymbol()) {
216 auto CsectAuxEntry = cantFail(Sym.getXCOFFCsectAuxRef());
217 if (!CsectAuxEntry.isLabel()) {
218 std::string MCStr =
219 "[" +
220 XCOFF::getMappingClassString(CsectAuxEntry.getStorageMappingClass())
221 .str() +
222 "]";
223 OS << left_justify(MCStr, 3);
224 }
225 }
226 OS << " " << format_hex(Sym.getSize(), 8);
227 OS << " " << Sym.getSectionNumber();
228 OS << " " << getStorageClassString(Sym.getStorageClass());
229 OS << " (idx: " << Obj.getSymbolIndex(Sym.getRawDataRefImpl().p) << ")";
230 if (Sym.isCsectSymbol()) {
231 if (auto ParentSym = getXCOFFSymbolContainingSymbolRef(Obj, Sym)) {
232 OS << " (csect idx: "
233 << Obj.getSymbolIndex(ParentSym->getRawDataRefImpl().p) << ")";
234 }
235 }
236 OS << "\n";
237}
238#endif
239
240Error XCOFFLinkGraphBuilder::processCsectsAndSymbols() {
241 LLVM_DEBUG(dbgs() << " Creating graph blocks and symbols...\n");
242
243 for ([[maybe_unused]] auto [K, V] : SectionTable) {
244 LLVM_DEBUG(dbgs() << " section entry(idx: " << K
245 << " section: " << V.Section->getName() << ")\n");
246 }
247
248 for (object::XCOFFSymbolRef Symbol : Obj.symbols()) {
249 LLVM_DEBUG({ printSymbolEntry(dbgs(), Obj, Symbol); });
250
251 auto Flags = Symbol.getFlags();
252 if (!Flags)
253 return Flags.takeError();
254
255 bool External = *Flags & object::SymbolRef::SF_Undefined;
258
259 auto SymbolIndex = Obj.getSymbolIndex(Symbol.getEntryAddress());
260 auto SymbolName = Symbol.getName();
261 if (!SymbolName)
262 return SymbolName.takeError();
263
264 if (External) {
265 LLVM_DEBUG(dbgs() << " created external symbol\n");
266 SymbolIndexTable[SymbolIndex] =
267 &G->addExternalSymbol(*SymbolName, Symbol.getSize(), Weak);
268 continue;
269 }
270
271 if (!Symbol.isCsectSymbol()) {
272 LLVM_DEBUG(dbgs() << " skipped: not a csect symbol\n");
273 continue;
274 }
275
276 auto ParentSym = getXCOFFSymbolContainingSymbolRef(Obj, Symbol);
277 object::XCOFFSymbolRef CsectSymbol = ParentSym ? *ParentSym : Symbol;
278
279 auto CsectSymbolIndex = Obj.getSymbolIndex(CsectSymbol.getEntryAddress());
280 auto ParentSectionNumber = CsectSymbol.getSectionNumber();
281
282 bool IsUndefinedSection = !SectionTable.contains(ParentSectionNumber);
283 Section *ParentSection = !IsUndefinedSection
284 ? SectionTable[ParentSectionNumber].Section
285 : UndefSection;
286 Block *B = nullptr;
287
288 // TODO: Clean up the logic for handling undefined symbols
289 if (!CsectTable.contains(CsectSymbolIndex) && !IsUndefinedSection) {
291 SectionTable[ParentSectionNumber].SectionData;
292 auto Data = SectionRef.getContents();
293 if (!Data)
294 return Data.takeError();
295 auto CsectSymbolAddr = CsectSymbol.getAddress();
296 if (!CsectSymbolAddr)
297 return CsectSymbolAddr.takeError();
298
299 ArrayRef<char> SectionBuffer{*Data};
300 auto Offset = *CsectSymbolAddr - SectionRef.getAddress();
301
302 LLVM_DEBUG(dbgs() << " symbol entry: offset = " << Offset
303 << ", size = " << CsectSymbol.getSize()
304 << ", storage class = "
305 << getStorageClassString(CsectSymbol.getStorageClass())
306 << "\n");
307
308 B = &G->createContentBlock(
309 *ParentSection, SectionBuffer.slice(Offset, CsectSymbol.getSize()),
310 orc::ExecutorAddr(*CsectSymbolAddr), CsectSymbol.getAlignment(), 0);
311
312 CsectTable[CsectSymbolIndex] = B;
313 } else {
314 B = CsectTable[CsectSymbolIndex];
315 }
316
318 if (Symbol.getSymbolType() & XCOFF::SYM_V_HIDDEN ||
319 Symbol.getSymbolType() & XCOFF::SYM_V_INTERNAL)
320 S = Scope::Hidden;
321 else if (Global)
322 S = Scope::Default;
323 // TODO: map all symbols for c++ static initialization to SideEffectOnly
324
326 auto SymbolAddr = Symbol.getAddress();
327 if (!SymbolAddr)
328 return SymbolAddr.takeError();
329 auto IsCallableOrErr = Symbol.isFunction();
330 if (!IsCallableOrErr)
331 return IsCallableOrErr.takeError();
332
333 auto BlockOffset = *SymbolAddr - B->getAddress().getValue();
334
335 LLVM_DEBUG(dbgs() << " creating with linkage = " << getLinkageName(L)
336 << ", scope = " << getScopeName(S) << ", B = "
337 << format_hex(B->getAddress().getValue(), 16) << "\n");
338
339 SymbolIndexTable[SymbolIndex] =
340 &G->addDefinedSymbol(*B, BlockOffset, *SymbolName, Symbol.getSize(), L,
341 S, *IsCallableOrErr, true);
342 }
343
344 return Error::success();
345}
346
347Error XCOFFLinkGraphBuilder::processRelocations() {
348 LLVM_DEBUG(dbgs() << " Creating relocations...\n");
349
350 for (object::SectionRef Section : Obj.sections()) {
351 auto SectionName = Section.getName();
352 if (!SectionName)
353 return SectionName.takeError();
354
355 LLVM_DEBUG(dbgs() << " Relocations for section " << *SectionName
356 << ":\n");
357
358 for (object::RelocationRef Relocation : Section.relocations()) {
359 SmallString<16> RelocName;
360 Relocation.getTypeName(RelocName);
361 object::SymbolRef Symbol = *Relocation.getSymbol();
362
363 auto TargetSymbol = Symbol.getName();
364 if (!TargetSymbol)
365 return TargetSymbol.takeError();
366
367 auto SymbolIndex = Obj.getSymbolIndex(Symbol.getRawDataRefImpl().p);
368
369 LLVM_DEBUG(dbgs() << " " << format_hex(Relocation.getOffset(), 16)
370 << " (idx: " << SymbolIndex << ")"
371 << " " << RelocName << " " << *TargetSymbol << "\n";);
372
373 assert(SymbolIndexTable.contains(SymbolIndex) &&
374 "Relocation needs a record in the symbol table");
375 auto *S = SymbolIndexTable[SymbolIndex];
376 auto It = find_if(G->blocks(),
377 [Target = orc::ExecutorAddr(Section.getAddress() +
378 Relocation.getOffset())](
379 const Block *B) -> bool {
380 return B->getRange().contains(Target);
381 });
382 assert(It != G->blocks().end() &&
383 "Cannot find the target relocation block");
384 Block *B = *It;
385
386 auto TargetBlockOffset = Section.getAddress() + Relocation.getOffset() -
387 B->getAddress().getValue();
388 switch (Relocation.getType()) {
389 case XCOFF::R_POS:
390 B->addEdge(ppc64::EdgeKind_ppc64::Pointer64, TargetBlockOffset, *S, 0);
391 break;
392 default:
393 SmallString<16> RelocType;
394 Relocation.getTypeName(RelocType);
395 return make_error<StringError>(
396 "Unsupported Relocation Type: " + RelocType, std::error_code());
397 }
398 }
399 }
400
401 return Error::success();
402}
403
405 LLVM_DEBUG(dbgs() << "Building XCOFFLinkGraph...\n");
406
407 // FIXME: Check to make sure the object is relocatable
408
409 if (auto Err = processSections())
410 return Err;
411 if (auto Err = processCsectsAndSymbols())
412 return Err;
413 if (auto Err = processRelocations())
414 return Err;
415
416 return std::move(G);
417}
418
419} // namespace jitlink
420} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static Expected< StringRef > getFileName(const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Symbol * Sym
Definition: ELF_riscv.cpp:479
#define G(x, y, z)
Definition: MD5.cpp:56
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
#define LLVM_DEBUG(...)
Definition: Debug.h:119
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition: DenseMap.h:156
Lightweight error class with error context and mandatory checking.
Definition: Error.h:159
static ErrorSuccess success()
Create a success value.
Definition: Error.h:336
Tagged union holding either a T or a Error.
Definition: Error.h:485
reference get()
Returns a reference to the stored T value.
Definition: Error.h:582
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:233
Manages the enabling and disabling of subtarget specific features.
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:47
section_iterator_range sections() const
Definition: ObjectFile.h:331
This is a value type class that represents a single relocation in the list of relocations in the obje...
Definition: ObjectFile.h:54
This is a value type class that represents a single section in the list of sections in the object fil...
Definition: ObjectFile.h:83
Expected< StringRef > getContents() const
Definition: ObjectFile.h:538
uint64_t getAddress() const
Definition: ObjectFile.h:526
This is a value type class that represents a single symbol in the list of symbols in the object file.
Definition: ObjectFile.h:170
uint32_t getAlignment() const
Get the alignment of this symbol as the actual value (not log 2).
Definition: ObjectFile.h:477
Expected< uint64_t > getAddress() const
Returns the symbol virtual address (i.e.
Definition: ObjectFile.h:469
uint32_t getSymbolIndex(uintptr_t SymEntPtr) const
XCOFFSymbolRef toSymbolRef(DataRefImpl Ref) const
uintptr_t getSymbolByIndex(uint32_t Idx) const
xcoff_symbol_iterator_range symbols() const
LLVM_ABI Expected< XCOFFCsectAuxRef > getXCOFFCsectAuxRef() const
LLVM_ABI bool isCsectSymbol() const
uintptr_t getEntryAddress() const
XCOFF::StorageClass getStorageClass() const
Represents an address in the executor process.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
LLVM_ABI StringRef getMappingClassString(XCOFF::StorageMappingClass SMC)
Definition: XCOFF.cpp:22
@ R_POS
Positive relocation.
Definition: XCOFF.h:264
@ SYM_V_HIDDEN
Definition: XCOFF.h:255
@ SYM_V_INTERNAL
Definition: XCOFF.h:254
StorageClass
Definition: XCOFF.h:171
@ C_BCOMM
Definition: XCOFF.h:178
@ C_GTLS
Definition: XCOFF.h:183
@ C_LINE
Definition: XCOFF.h:229
@ C_DECL
Definition: XCOFF.h:209
@ C_PSYM
Definition: XCOFF.h:191
@ C_RPSYM
Definition: XCOFF.h:193
@ C_STRTAG
Definition: XCOFF.h:219
@ C_FIELD
Definition: XCOFF.h:227
@ C_GSYM
Definition: XCOFF.h:176
@ C_BINCL
Definition: XCOFF.h:174
@ C_UNTAG
Definition: XCOFF.h:221
@ C_AUTO
Definition: XCOFF.h:212
@ C_RSYM
Definition: XCOFF.h:192
@ C_EXTDEF
Definition: XCOFF.h:214
@ C_LABEL
Definition: XCOFF.h:215
@ C_BLOCK
Definition: XCOFF.h:205
@ C_STAT
Definition: XCOFF.h:204
@ C_INFO
Definition: XCOFF.h:208
@ C_ENTRY
Definition: XCOFF.h:180
@ C_STTLS
Definition: XCOFF.h:184
@ C_WEAKEXT
Definition: XCOFF.h:200
@ C_ENTAG
Definition: XCOFF.h:224
@ C_EINCL
Definition: XCOFF.h:175
@ C_LSYM
Definition: XCOFF.h:190
@ C_ALIAS
Definition: XCOFF.h:230
@ C_EFCN
Definition: XCOFF.h:232
@ C_ULABEL
Definition: XCOFF.h:216
@ C_FILE
Definition: XCOFF.h:173
@ C_NULL
Definition: XCOFF.h:203
@ C_STSYM
Definition: XCOFF.h:177
@ C_ECOML
Definition: XCOFF.h:194
@ C_DWARF
Definition: XCOFF.h:187
@ C_HIDDEN
Definition: XCOFF.h:231
@ C_REGPARM
Definition: XCOFF.h:226
@ C_TPDEF
Definition: XCOFF.h:222
@ C_USTATIC
Definition: XCOFF.h:223
@ C_HIDEXT
Definition: XCOFF.h:207
@ C_TCSYM
Definition: XCOFF.h:235
@ C_ECOMM
Definition: XCOFF.h:179
@ C_BSTAT
Definition: XCOFF.h:181
@ C_ESTAT
Definition: XCOFF.h:182
MemProt
Describes Read/Write/Exec permissions for memory.
Definition: MemoryFlags.h:27
NodeAddr< BlockNode * > Block
Definition: RDFGraph.h:392
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:477
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:207
FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false)
format_hex - Output N as a fixed width hexadecimal.
Definition: Format.h:188
FormattedNumber format_hex_no_prefix(uint64_t N, unsigned Width, bool Upper=false)
format_hex_no_prefix - Output N as a fixed width hexadecimal.
Definition: Format.h:201
@ Global
Append to llvm.global_dtors.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:769
FormattedString left_justify(StringRef Str, unsigned Width)
left_justify - append spaces after string so total output is Width characters.
Definition: Format.h:147
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1886
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1777
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:851