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 =
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,
212 const object::XCOFFSymbolRef &Sym) {
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) {
290 object::SectionRef &SectionRef =
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);
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)
#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.
#define LLVM_DEBUG(...)
Definition Debug.h:119
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
Definition ArrayRef.h:191
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
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.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
DataRefImpl getRawDataRefImpl() const
section_iterator_range sections() const
Definition ObjectFile.h:331
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
LLVM_ABI Expected< StringRef > getName() const
uintptr_t getEntryAddress() const
XCOFF::StorageClass getStorageClass() const
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.
const char SectionName[]
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
@ C_WEAKEXT
Definition XCOFF.h:200
@ C_REGPARM
Definition XCOFF.h:226
@ C_USTATIC
Definition XCOFF.h:223
MemProt
Describes Read/Write/Exec permissions for memory.
Definition MemoryFlags.h:27
This is an optimization pass for GlobalISel generic memory operations.
@ 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
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
@ 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
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:189
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:1869
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:1760
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:851