Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===- ObjectFile.h - File format independent object file -------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file declares a file format independent ObjectFile class.
10
//
11
//===----------------------------------------------------------------------===//
12
 
13
#ifndef LLVM_OBJECT_OBJECTFILE_H
14
#define LLVM_OBJECT_OBJECTFILE_H
15
 
16
#include "llvm/ADT/ArrayRef.h"
17
#include "llvm/ADT/Hashing.h"
18
#include "llvm/ADT/StringRef.h"
19
#include "llvm/ADT/Triple.h"
20
#include "llvm/ADT/iterator_range.h"
21
#include "llvm/BinaryFormat/Magic.h"
22
#include "llvm/BinaryFormat/Swift.h"
23
#include "llvm/Object/Binary.h"
24
#include "llvm/Object/Error.h"
25
#include "llvm/Object/SymbolicFile.h"
26
#include "llvm/Support/Casting.h"
27
#include "llvm/Support/Error.h"
28
#include "llvm/Support/MemoryBufferRef.h"
29
#include <cassert>
30
#include <cstdint>
31
#include <memory>
32
 
33
namespace llvm {
34
 
35
class SubtargetFeatures;
36
 
37
namespace object {
38
 
39
class COFFObjectFile;
40
class MachOObjectFile;
41
class ObjectFile;
42
class SectionRef;
43
class SymbolRef;
44
class symbol_iterator;
45
class WasmObjectFile;
46
 
47
using section_iterator = content_iterator<SectionRef>;
48
 
49
/// This is a value type class that represents a single relocation in the list
50
/// of relocations in the object file.
51
class RelocationRef {
52
  DataRefImpl RelocationPimpl;
53
  const ObjectFile *OwningObject = nullptr;
54
 
55
public:
56
  RelocationRef() = default;
57
  RelocationRef(DataRefImpl RelocationP, const ObjectFile *Owner);
58
 
59
  bool operator==(const RelocationRef &Other) const;
60
 
61
  void moveNext();
62
 
63
  uint64_t getOffset() const;
64
  symbol_iterator getSymbol() const;
65
  uint64_t getType() const;
66
 
67
  /// Get a string that represents the type of this relocation.
68
  ///
69
  /// This is for display purposes only.
70
  void getTypeName(SmallVectorImpl<char> &Result) const;
71
 
72
  DataRefImpl getRawDataRefImpl() const;
73
  const ObjectFile *getObject() const;
74
};
75
 
76
using relocation_iterator = content_iterator<RelocationRef>;
77
 
78
/// This is a value type class that represents a single section in the list of
79
/// sections in the object file.
80
class SectionRef {
81
  friend class SymbolRef;
82
 
83
  DataRefImpl SectionPimpl;
84
  const ObjectFile *OwningObject = nullptr;
85
 
86
public:
87
  SectionRef() = default;
88
  SectionRef(DataRefImpl SectionP, const ObjectFile *Owner);
89
 
90
  bool operator==(const SectionRef &Other) const;
91
  bool operator!=(const SectionRef &Other) const;
92
  bool operator<(const SectionRef &Other) const;
93
 
94
  void moveNext();
95
 
96
  Expected<StringRef> getName() const;
97
  uint64_t getAddress() const;
98
  uint64_t getIndex() const;
99
  uint64_t getSize() const;
100
  Expected<StringRef> getContents() const;
101
 
102
  /// Get the alignment of this section.
103
  Align getAlignment() const;
104
 
105
  bool isCompressed() const;
106
  /// Whether this section contains instructions.
107
  bool isText() const;
108
  /// Whether this section contains data, not instructions.
109
  bool isData() const;
110
  /// Whether this section contains BSS uninitialized data.
111
  bool isBSS() const;
112
  bool isVirtual() const;
113
  bool isBitcode() const;
114
  bool isStripped() const;
115
 
116
  /// Whether this section will be placed in the text segment, according to the
117
  /// Berkeley size format. This is true if the section is allocatable, and
118
  /// contains either code or readonly data.
119
  bool isBerkeleyText() const;
120
  /// Whether this section will be placed in the data segment, according to the
121
  /// Berkeley size format. This is true if the section is allocatable and
122
  /// contains data (e.g. PROGBITS), but is not text.
123
  bool isBerkeleyData() const;
124
 
125
  /// Whether this section is a debug section.
126
  bool isDebugSection() const;
127
 
128
  bool containsSymbol(SymbolRef S) const;
129
 
130
  relocation_iterator relocation_begin() const;
131
  relocation_iterator relocation_end() const;
132
  iterator_range<relocation_iterator> relocations() const {
133
    return make_range(relocation_begin(), relocation_end());
134
  }
135
 
136
  /// Returns the related section if this section contains relocations. The
137
  /// returned section may or may not have applied its relocations.
138
  Expected<section_iterator> getRelocatedSection() const;
139
 
140
  DataRefImpl getRawDataRefImpl() const;
141
  const ObjectFile *getObject() const;
142
};
143
 
144
struct SectionedAddress {
145
  const static uint64_t UndefSection = UINT64_MAX;
146
 
147
  uint64_t Address = 0;
148
  uint64_t SectionIndex = UndefSection;
149
};
150
 
151
inline bool operator<(const SectionedAddress &LHS,
152
                      const SectionedAddress &RHS) {
153
  return std::tie(LHS.SectionIndex, LHS.Address) <
154
         std::tie(RHS.SectionIndex, RHS.Address);
155
}
156
 
157
inline bool operator==(const SectionedAddress &LHS,
158
                       const SectionedAddress &RHS) {
159
  return std::tie(LHS.SectionIndex, LHS.Address) ==
160
         std::tie(RHS.SectionIndex, RHS.Address);
161
}
162
 
163
raw_ostream &operator<<(raw_ostream &OS, const SectionedAddress &Addr);
164
 
165
/// This is a value type class that represents a single symbol in the list of
166
/// symbols in the object file.
167
class SymbolRef : public BasicSymbolRef {
168
  friend class SectionRef;
169
 
170
public:
171
  enum Type {
172
    ST_Unknown, // Type not specified
173
    ST_Other,
174
    ST_Data,
175
    ST_Debug,
176
    ST_File,
177
    ST_Function,
178
  };
179
 
180
  SymbolRef() = default;
181
  SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner);
182
  SymbolRef(const BasicSymbolRef &B) : BasicSymbolRef(B) {
183
    assert(isa<ObjectFile>(BasicSymbolRef::getObject()));
184
  }
185
 
186
  Expected<StringRef> getName() const;
187
  /// Returns the symbol virtual address (i.e. address at which it will be
188
  /// mapped).
189
  Expected<uint64_t> getAddress() const;
190
 
191
  /// Return the value of the symbol depending on the object this can be an
192
  /// offset or a virtual address.
193
  Expected<uint64_t> getValue() const;
194
 
195
  /// Get the alignment of this symbol as the actual value (not log 2).
196
  uint32_t getAlignment() const;
197
  uint64_t getCommonSize() const;
198
  Expected<SymbolRef::Type> getType() const;
199
 
200
  /// Get section this symbol is defined in reference to. Result is
201
  /// end_sections() if it is undefined or is an absolute symbol.
202
  Expected<section_iterator> getSection() const;
203
 
204
  const ObjectFile *getObject() const;
205
};
206
 
207
class symbol_iterator : public basic_symbol_iterator {
208
public:
209
  symbol_iterator(SymbolRef Sym) : basic_symbol_iterator(Sym) {}
210
  symbol_iterator(const basic_symbol_iterator &B)
211
      : basic_symbol_iterator(SymbolRef(B->getRawDataRefImpl(),
212
                                        cast<ObjectFile>(B->getObject()))) {}
213
 
214
  const SymbolRef *operator->() const {
215
    const BasicSymbolRef &P = basic_symbol_iterator::operator *();
216
    return static_cast<const SymbolRef*>(&P);
217
  }
218
 
219
  const SymbolRef &operator*() const {
220
    const BasicSymbolRef &P = basic_symbol_iterator::operator *();
221
    return static_cast<const SymbolRef&>(P);
222
  }
223
};
224
 
225
/// This class is the base class for all object file types. Concrete instances
226
/// of this object are created by createObjectFile, which figures out which type
227
/// to create.
228
class ObjectFile : public SymbolicFile {
229
  virtual void anchor();
230
 
231
protected:
232
  ObjectFile(unsigned int Type, MemoryBufferRef Source);
233
 
234
  const uint8_t *base() const {
235
    return reinterpret_cast<const uint8_t *>(Data.getBufferStart());
236
  }
237
 
238
  // These functions are for SymbolRef to call internally. The main goal of
239
  // this is to allow SymbolRef::SymbolPimpl to point directly to the symbol
240
  // entry in the memory mapped object file. SymbolPimpl cannot contain any
241
  // virtual functions because then it could not point into the memory mapped
242
  // file.
243
  //
244
  // Implementations assume that the DataRefImpl is valid and has not been
245
  // modified externally. It's UB otherwise.
246
  friend class SymbolRef;
247
 
248
  virtual Expected<StringRef> getSymbolName(DataRefImpl Symb) const = 0;
249
  Error printSymbolName(raw_ostream &OS,
250
                                  DataRefImpl Symb) const override;
251
  virtual Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const = 0;
252
  virtual uint64_t getSymbolValueImpl(DataRefImpl Symb) const = 0;
253
  virtual uint32_t getSymbolAlignment(DataRefImpl Symb) const;
254
  virtual uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const = 0;
255
  virtual Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const = 0;
256
  virtual Expected<section_iterator>
257
  getSymbolSection(DataRefImpl Symb) const = 0;
258
 
259
  // Same as above for SectionRef.
260
  friend class SectionRef;
261
 
262
  virtual void moveSectionNext(DataRefImpl &Sec) const = 0;
263
  virtual Expected<StringRef> getSectionName(DataRefImpl Sec) const = 0;
264
  virtual uint64_t getSectionAddress(DataRefImpl Sec) const = 0;
265
  virtual uint64_t getSectionIndex(DataRefImpl Sec) const = 0;
266
  virtual uint64_t getSectionSize(DataRefImpl Sec) const = 0;
267
  virtual Expected<ArrayRef<uint8_t>>
268
  getSectionContents(DataRefImpl Sec) const = 0;
269
  virtual uint64_t getSectionAlignment(DataRefImpl Sec) const = 0;
270
  virtual bool isSectionCompressed(DataRefImpl Sec) const = 0;
271
  virtual bool isSectionText(DataRefImpl Sec) const = 0;
272
  virtual bool isSectionData(DataRefImpl Sec) const = 0;
273
  virtual bool isSectionBSS(DataRefImpl Sec) const = 0;
274
  // A section is 'virtual' if its contents aren't present in the object image.
275
  virtual bool isSectionVirtual(DataRefImpl Sec) const = 0;
276
  virtual bool isSectionBitcode(DataRefImpl Sec) const;
277
  virtual bool isSectionStripped(DataRefImpl Sec) const;
278
  virtual bool isBerkeleyText(DataRefImpl Sec) const;
279
  virtual bool isBerkeleyData(DataRefImpl Sec) const;
280
  virtual bool isDebugSection(DataRefImpl Sec) const;
281
  virtual relocation_iterator section_rel_begin(DataRefImpl Sec) const = 0;
282
  virtual relocation_iterator section_rel_end(DataRefImpl Sec) const = 0;
283
  virtual Expected<section_iterator> getRelocatedSection(DataRefImpl Sec) const;
284
 
285
  // Same as above for RelocationRef.
286
  friend class RelocationRef;
287
  virtual void moveRelocationNext(DataRefImpl &Rel) const = 0;
288
  virtual uint64_t getRelocationOffset(DataRefImpl Rel) const = 0;
289
  virtual symbol_iterator getRelocationSymbol(DataRefImpl Rel) const = 0;
290
  virtual uint64_t getRelocationType(DataRefImpl Rel) const = 0;
291
  virtual void getRelocationTypeName(DataRefImpl Rel,
292
                                     SmallVectorImpl<char> &Result) const = 0;
293
 
294
  virtual llvm::binaryformat::Swift5ReflectionSectionKind
295
  mapReflectionSectionNameToEnumValue(StringRef SectionName) const {
296
    return llvm::binaryformat::Swift5ReflectionSectionKind::unknown;
297
  };
298
 
299
  Expected<uint64_t> getSymbolValue(DataRefImpl Symb) const;
300
 
301
public:
302
  ObjectFile() = delete;
303
  ObjectFile(const ObjectFile &other) = delete;
304
 
305
  uint64_t getCommonSymbolSize(DataRefImpl Symb) const {
306
    Expected<uint32_t> SymbolFlagsOrErr = getSymbolFlags(Symb);
307
    if (!SymbolFlagsOrErr)
308
      // TODO: Actually report errors helpfully.
309
      report_fatal_error(SymbolFlagsOrErr.takeError());
310
    assert(*SymbolFlagsOrErr & SymbolRef::SF_Common);
311
    return getCommonSymbolSizeImpl(Symb);
312
  }
313
 
314
  virtual std::vector<SectionRef> dynamic_relocation_sections() const {
315
    return std::vector<SectionRef>();
316
  }
317
 
318
  using symbol_iterator_range = iterator_range<symbol_iterator>;
319
  symbol_iterator_range symbols() const {
320
    return symbol_iterator_range(symbol_begin(), symbol_end());
321
  }
322
 
323
  virtual section_iterator section_begin() const = 0;
324
  virtual section_iterator section_end() const = 0;
325
 
326
  using section_iterator_range = iterator_range<section_iterator>;
327
  section_iterator_range sections() const {
328
    return section_iterator_range(section_begin(), section_end());
329
  }
330
 
331
  virtual bool hasDebugInfo() const;
332
 
333
  /// The number of bytes used to represent an address in this object
334
  ///        file format.
335
  virtual uint8_t getBytesInAddress() const = 0;
336
 
337
  virtual StringRef getFileFormatName() const = 0;
338
  virtual Triple::ArchType getArch() const = 0;
339
  virtual Expected<SubtargetFeatures> getFeatures() const = 0;
340
  virtual std::optional<StringRef> tryGetCPUName() const {
341
    return std::nullopt;
342
  };
343
  virtual void setARMSubArch(Triple &TheTriple) const { }
344
  virtual Expected<uint64_t> getStartAddress() const {
345
    return errorCodeToError(object_error::parse_failed);
346
  };
347
 
348
  /// Create a triple from the data in this object file.
349
  Triple makeTriple() const;
350
 
351
  /// Maps a debug section name to a standard DWARF section name.
352
  virtual StringRef mapDebugSectionName(StringRef Name) const { return Name; }
353
 
354
  /// True if this is a relocatable object (.o/.obj).
355
  virtual bool isRelocatableObject() const = 0;
356
 
357
  /// True if the reflection section can be stripped by the linker.
358
  bool isReflectionSectionStrippable(
359
      llvm::binaryformat::Swift5ReflectionSectionKind ReflectionSectionKind)
360
      const;
361
 
362
  /// @returns Pointer to ObjectFile subclass to handle this type of object.
363
  /// @param ObjectPath The path to the object file. ObjectPath.isObject must
364
  ///        return true.
365
  /// Create ObjectFile from path.
366
  static Expected<OwningBinary<ObjectFile>>
367
  createObjectFile(StringRef ObjectPath);
368
 
369
  static Expected<std::unique_ptr<ObjectFile>>
370
  createObjectFile(MemoryBufferRef Object, llvm::file_magic Type,
371
                   bool InitContent = true);
372
  static Expected<std::unique_ptr<ObjectFile>>
373
  createObjectFile(MemoryBufferRef Object) {
374
    return createObjectFile(Object, llvm::file_magic::unknown);
375
  }
376
 
377
  static bool classof(const Binary *v) {
378
    return v->isObject();
379
  }
380
 
381
  static Expected<std::unique_ptr<COFFObjectFile>>
382
  createCOFFObjectFile(MemoryBufferRef Object);
383
 
384
  static Expected<std::unique_ptr<ObjectFile>>
385
  createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType);
386
 
387
  static Expected<std::unique_ptr<ObjectFile>>
388
  createELFObjectFile(MemoryBufferRef Object, bool InitContent = true);
389
 
390
  static Expected<std::unique_ptr<MachOObjectFile>>
391
  createMachOObjectFile(MemoryBufferRef Object,
392
                        uint32_t UniversalCputype = 0,
393
                        uint32_t UniversalIndex = 0);
394
 
395
  static Expected<std::unique_ptr<WasmObjectFile>>
396
  createWasmObjectFile(MemoryBufferRef Object);
397
};
398
 
399
// Inline function definitions.
400
inline SymbolRef::SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner)
401
    : BasicSymbolRef(SymbolP, Owner) {}
402
 
403
inline Expected<StringRef> SymbolRef::getName() const {
404
  return getObject()->getSymbolName(getRawDataRefImpl());
405
}
406
 
407
inline Expected<uint64_t> SymbolRef::getAddress() const {
408
  return getObject()->getSymbolAddress(getRawDataRefImpl());
409
}
410
 
411
inline Expected<uint64_t> SymbolRef::getValue() const {
412
  return getObject()->getSymbolValue(getRawDataRefImpl());
413
}
414
 
415
inline uint32_t SymbolRef::getAlignment() const {
416
  return getObject()->getSymbolAlignment(getRawDataRefImpl());
417
}
418
 
419
inline uint64_t SymbolRef::getCommonSize() const {
420
  return getObject()->getCommonSymbolSize(getRawDataRefImpl());
421
}
422
 
423
inline Expected<section_iterator> SymbolRef::getSection() const {
424
  return getObject()->getSymbolSection(getRawDataRefImpl());
425
}
426
 
427
inline Expected<SymbolRef::Type> SymbolRef::getType() const {
428
  return getObject()->getSymbolType(getRawDataRefImpl());
429
}
430
 
431
inline const ObjectFile *SymbolRef::getObject() const {
432
  const SymbolicFile *O = BasicSymbolRef::getObject();
433
  return cast<ObjectFile>(O);
434
}
435
 
436
/// SectionRef
437
inline SectionRef::SectionRef(DataRefImpl SectionP,
438
                              const ObjectFile *Owner)
439
  : SectionPimpl(SectionP)
440
  , OwningObject(Owner) {}
441
 
442
inline bool SectionRef::operator==(const SectionRef &Other) const {
443
  return OwningObject == Other.OwningObject &&
444
         SectionPimpl == Other.SectionPimpl;
445
}
446
 
447
inline bool SectionRef::operator!=(const SectionRef &Other) const {
448
  return !(*this == Other);
449
}
450
 
451
inline bool SectionRef::operator<(const SectionRef &Other) const {
452
  assert(OwningObject == Other.OwningObject);
453
  return SectionPimpl < Other.SectionPimpl;
454
}
455
 
456
inline void SectionRef::moveNext() {
457
  return OwningObject->moveSectionNext(SectionPimpl);
458
}
459
 
460
inline Expected<StringRef> SectionRef::getName() const {
461
  return OwningObject->getSectionName(SectionPimpl);
462
}
463
 
464
inline uint64_t SectionRef::getAddress() const {
465
  return OwningObject->getSectionAddress(SectionPimpl);
466
}
467
 
468
inline uint64_t SectionRef::getIndex() const {
469
  return OwningObject->getSectionIndex(SectionPimpl);
470
}
471
 
472
inline uint64_t SectionRef::getSize() const {
473
  return OwningObject->getSectionSize(SectionPimpl);
474
}
475
 
476
inline Expected<StringRef> SectionRef::getContents() const {
477
  Expected<ArrayRef<uint8_t>> Res =
478
      OwningObject->getSectionContents(SectionPimpl);
479
  if (!Res)
480
    return Res.takeError();
481
  return StringRef(reinterpret_cast<const char *>(Res->data()), Res->size());
482
}
483
 
484
inline Align SectionRef::getAlignment() const {
485
  return MaybeAlign(OwningObject->getSectionAlignment(SectionPimpl))
486
      .valueOrOne();
487
}
488
 
489
inline bool SectionRef::isCompressed() const {
490
  return OwningObject->isSectionCompressed(SectionPimpl);
491
}
492
 
493
inline bool SectionRef::isText() const {
494
  return OwningObject->isSectionText(SectionPimpl);
495
}
496
 
497
inline bool SectionRef::isData() const {
498
  return OwningObject->isSectionData(SectionPimpl);
499
}
500
 
501
inline bool SectionRef::isBSS() const {
502
  return OwningObject->isSectionBSS(SectionPimpl);
503
}
504
 
505
inline bool SectionRef::isVirtual() const {
506
  return OwningObject->isSectionVirtual(SectionPimpl);
507
}
508
 
509
inline bool SectionRef::isBitcode() const {
510
  return OwningObject->isSectionBitcode(SectionPimpl);
511
}
512
 
513
inline bool SectionRef::isStripped() const {
514
  return OwningObject->isSectionStripped(SectionPimpl);
515
}
516
 
517
inline bool SectionRef::isBerkeleyText() const {
518
  return OwningObject->isBerkeleyText(SectionPimpl);
519
}
520
 
521
inline bool SectionRef::isBerkeleyData() const {
522
  return OwningObject->isBerkeleyData(SectionPimpl);
523
}
524
 
525
inline bool SectionRef::isDebugSection() const {
526
  return OwningObject->isDebugSection(SectionPimpl);
527
}
528
 
529
inline relocation_iterator SectionRef::relocation_begin() const {
530
  return OwningObject->section_rel_begin(SectionPimpl);
531
}
532
 
533
inline relocation_iterator SectionRef::relocation_end() const {
534
  return OwningObject->section_rel_end(SectionPimpl);
535
}
536
 
537
inline Expected<section_iterator> SectionRef::getRelocatedSection() const {
538
  return OwningObject->getRelocatedSection(SectionPimpl);
539
}
540
 
541
inline DataRefImpl SectionRef::getRawDataRefImpl() const {
542
  return SectionPimpl;
543
}
544
 
545
inline const ObjectFile *SectionRef::getObject() const {
546
  return OwningObject;
547
}
548
 
549
/// RelocationRef
550
inline RelocationRef::RelocationRef(DataRefImpl RelocationP,
551
                              const ObjectFile *Owner)
552
  : RelocationPimpl(RelocationP)
553
  , OwningObject(Owner) {}
554
 
555
inline bool RelocationRef::operator==(const RelocationRef &Other) const {
556
  return RelocationPimpl == Other.RelocationPimpl;
557
}
558
 
559
inline void RelocationRef::moveNext() {
560
  return OwningObject->moveRelocationNext(RelocationPimpl);
561
}
562
 
563
inline uint64_t RelocationRef::getOffset() const {
564
  return OwningObject->getRelocationOffset(RelocationPimpl);
565
}
566
 
567
inline symbol_iterator RelocationRef::getSymbol() const {
568
  return OwningObject->getRelocationSymbol(RelocationPimpl);
569
}
570
 
571
inline uint64_t RelocationRef::getType() const {
572
  return OwningObject->getRelocationType(RelocationPimpl);
573
}
574
 
575
inline void RelocationRef::getTypeName(SmallVectorImpl<char> &Result) const {
576
  return OwningObject->getRelocationTypeName(RelocationPimpl, Result);
577
}
578
 
579
inline DataRefImpl RelocationRef::getRawDataRefImpl() const {
580
  return RelocationPimpl;
581
}
582
 
583
inline const ObjectFile *RelocationRef::getObject() const {
584
  return OwningObject;
585
}
586
 
587
} // end namespace object
588
 
589
template <> struct DenseMapInfo<object::SectionRef> {
590
  static bool isEqual(const object::SectionRef &A,
591
                      const object::SectionRef &B) {
592
    return A == B;
593
  }
594
  static object::SectionRef getEmptyKey() {
595
    return object::SectionRef({}, nullptr);
596
  }
597
  static object::SectionRef getTombstoneKey() {
598
    object::DataRefImpl TS;
599
    TS.p = (uintptr_t)-1;
600
    return object::SectionRef(TS, nullptr);
601
  }
602
  static unsigned getHashValue(const object::SectionRef &Sec) {
603
    object::DataRefImpl Raw = Sec.getRawDataRefImpl();
604
    return hash_combine(Raw.p, Raw.d.a, Raw.d.b);
605
  }
606
};
607
 
608
} // end namespace llvm
609
 
610
#endif // LLVM_OBJECT_OBJECTFILE_H