xref: /llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp (revision fd75ee9154d25a7ac4b806a193ef7ad846703c0c)
1 //===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===//
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 defines the XCOFFObjectFile class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/Object/XCOFFObjectFile.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/Support/BinaryStreamReader.h"
16 #include "llvm/Support/Endian.h"
17 #include "llvm/Support/ErrorHandling.h"
18 #include "llvm/Support/MathExtras.h"
19 #include <cstddef>
20 #include <cstring>
21 
22 namespace llvm {
23 namespace object {
24 
25 enum { XCOFF32FileHeaderSize = 20 };
26 static_assert(sizeof(XCOFFFileHeader) == XCOFF32FileHeaderSize,
27               "Wrong size for XCOFF file header.");
28 
29 // Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
30 // Returns unexpected_eof on error.
31 template <typename T>
32 static std::error_code getObject(const T *&Obj, MemoryBufferRef M,
33                                  const void *Ptr,
34                                  const uint64_t Size = sizeof(T)) {
35   uintptr_t Addr = uintptr_t(Ptr);
36   if (std::error_code EC = Binary::checkOffset(M, Addr, Size))
37     return EC;
38   Obj = reinterpret_cast<const T *>(Addr);
39   return std::error_code();
40 }
41 
42 template <typename T> static const T *viewAs(uintptr_t in) {
43   return reinterpret_cast<const T *>(in);
44 }
45 
46 const XCOFFSectionHeader *XCOFFObjectFile::toSection(DataRefImpl Ref) const {
47   auto Sec = viewAs<XCOFFSectionHeader>(Ref.p);
48 #ifndef NDEBUG
49   if (Sec < SectionHdrTablePtr ||
50       Sec >= (SectionHdrTablePtr + getNumberOfSections()))
51     report_fatal_error("Section header outside of section header table.");
52 
53   uintptr_t Offset = uintptr_t(Sec) - uintptr_t(SectionHdrTablePtr);
54   if (Offset % getSectionHeaderSize() != 0)
55     report_fatal_error(
56         "Section header pointer does not point to a valid section header.");
57 #endif
58   return Sec;
59 }
60 
61 // The next 2 functions are not exactly necessary yet, but they are useful to
62 // abstract over the size difference between XCOFF32 and XCOFF64 structure
63 // definitions.
64 size_t XCOFFObjectFile::getFileHeaderSize() const {
65   return sizeof(XCOFFFileHeader);
66 }
67 
68 size_t XCOFFObjectFile::getSectionHeaderSize() const {
69   return sizeof(XCOFFSectionHeader);
70 }
71 
72 void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
73   llvm_unreachable("Not yet implemented!");
74   return;
75 }
76 
77 Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
78   StringRef Result;
79   llvm_unreachable("Not yet implemented!");
80   return Result;
81 }
82 
83 Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
84   uint64_t Result = 0;
85   llvm_unreachable("Not yet implemented!");
86   return Result;
87 }
88 
89 uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
90   uint64_t Result = 0;
91   llvm_unreachable("Not yet implemented!");
92   return Result;
93 }
94 
95 uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
96   uint64_t Result = 0;
97   llvm_unreachable("Not yet implemented!");
98   return Result;
99 }
100 
101 Expected<SymbolRef::Type>
102 XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
103   llvm_unreachable("Not yet implemented!");
104   return SymbolRef::ST_Other;
105 }
106 
107 Expected<section_iterator>
108 XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
109   llvm_unreachable("Not yet implemented!");
110   return section_iterator(SectionRef());
111 }
112 
113 void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
114   const char *Ptr = reinterpret_cast<const char *>(Sec.p);
115   Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize());
116 }
117 
118 Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {
119   const char *Name = toSection(Sec)->Name;
120   auto NulCharPtr =
121       static_cast<const char *>(memchr(Name, '\0', XCOFF::SectionNameSize));
122   return NulCharPtr ? StringRef(Name, NulCharPtr - Name)
123                     : StringRef(Name, XCOFF::SectionNameSize);
124 }
125 
126 uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
127   return toSection(Sec)->VirtualAddress;
128 }
129 
130 uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
131   // Section numbers in XCOFF are numbered beginning at 1. A section number of
132   // zero is used to indicate that a symbol is being imported or is undefined.
133   return toSection(Sec) - SectionHdrTablePtr + 1;
134 }
135 
136 uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
137   return toSection(Sec)->SectionSize;
138 }
139 
140 std::error_code XCOFFObjectFile::getSectionContents(DataRefImpl Sec,
141                                                     StringRef &Res) const {
142   llvm_unreachable("Not yet implemented!");
143   return std::error_code();
144 }
145 
146 uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
147   uint64_t Result = 0;
148   llvm_unreachable("Not yet implemented!");
149   return Result;
150 }
151 
152 bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
153   bool Result = false;
154   llvm_unreachable("Not yet implemented!");
155   return Result;
156 }
157 
158 bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {
159   return toSection(Sec)->Flags & XCOFF::STYP_TEXT;
160 }
161 
162 bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {
163   unsigned Flags = toSection(Sec)->Flags;
164   return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);
165 }
166 
167 bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {
168   unsigned Flags = toSection(Sec)->Flags;
169   return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);
170 }
171 
172 bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {
173   bool Result = false;
174   llvm_unreachable("Not yet implemented!");
175   return Result;
176 }
177 
178 relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {
179   llvm_unreachable("Not yet implemented!");
180   return relocation_iterator(RelocationRef());
181 }
182 
183 relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const {
184   llvm_unreachable("Not yet implemented!");
185   return relocation_iterator(RelocationRef());
186 }
187 
188 void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
189   llvm_unreachable("Not yet implemented!");
190   return;
191 }
192 
193 uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
194   llvm_unreachable("Not yet implemented!");
195   uint64_t Result = 0;
196   return Result;
197 }
198 
199 symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
200   llvm_unreachable("Not yet implemented!");
201   return symbol_iterator(SymbolRef());
202 }
203 
204 uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
205   llvm_unreachable("Not yet implemented!");
206   uint64_t Result = 0;
207   return Result;
208 }
209 
210 void XCOFFObjectFile::getRelocationTypeName(
211     DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
212   llvm_unreachable("Not yet implemented!");
213   return;
214 }
215 
216 uint32_t XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
217   uint32_t Result = 0;
218   llvm_unreachable("Not yet implemented!");
219   return Result;
220 }
221 
222 basic_symbol_iterator XCOFFObjectFile::symbol_begin() const {
223   llvm_unreachable("Not yet implemented!");
224   return basic_symbol_iterator(SymbolRef());
225 }
226 
227 basic_symbol_iterator XCOFFObjectFile::symbol_end() const {
228   llvm_unreachable("Not yet implemented!");
229   return basic_symbol_iterator(SymbolRef());
230 }
231 
232 section_iterator XCOFFObjectFile::section_begin() const {
233   DataRefImpl DRI;
234   DRI.p = reinterpret_cast<uintptr_t>(SectionHdrTablePtr);
235   return section_iterator(SectionRef(DRI, this));
236 }
237 
238 section_iterator XCOFFObjectFile::section_end() const {
239   DataRefImpl DRI;
240   DRI.p =
241       reinterpret_cast<uintptr_t>(SectionHdrTablePtr + getNumberOfSections());
242   return section_iterator(SectionRef(DRI, this));
243 }
244 
245 uint8_t XCOFFObjectFile::getBytesInAddress() const {
246   // Only support 32-bit object files for now ...
247   assert(getFileHeaderSize() ==  XCOFF32FileHeaderSize);
248   return 4;
249 }
250 
251 StringRef XCOFFObjectFile::getFileFormatName() const {
252   assert(getFileHeaderSize() == XCOFF32FileHeaderSize);
253   return "aixcoff-rs6000";
254 }
255 
256 Triple::ArchType XCOFFObjectFile::getArch() const {
257   assert(getFileHeaderSize() == XCOFF32FileHeaderSize);
258   return Triple::ppc;
259 }
260 
261 SubtargetFeatures XCOFFObjectFile::getFeatures() const {
262   llvm_unreachable("Not yet implemented!");
263   return SubtargetFeatures();
264 }
265 
266 bool XCOFFObjectFile::isRelocatableObject() const {
267   bool Result = false;
268   llvm_unreachable("Not yet implemented!");
269   return Result;
270 }
271 
272 Expected<uint64_t> XCOFFObjectFile::getStartAddress() const {
273   // TODO FIXME Should get from auxiliary_header->o_entry when support for the
274   // auxiliary_header is added.
275   return 0;
276 }
277 
278 XCOFFObjectFile::XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
279     : ObjectFile(Binary::ID_XCOFF32, Object) {
280 
281   // Current location within the file.
282   uint64_t CurPtr = 0;
283 
284   if ((EC = getObject(FileHdrPtr, Data, base() + CurPtr)))
285     return;
286 
287   CurPtr += getFileHeaderSize();
288   // TODO FIXME we don't have support for an optional header yet, so just skip
289   // past it.
290   CurPtr += FileHdrPtr->AuxHeaderSize;
291 
292   if (getNumberOfSections() != 0) {
293     if ((EC = getObject(SectionHdrTablePtr, Data, base() + CurPtr,
294                         getNumberOfSections() * getSectionHeaderSize())))
295       return;
296   }
297 }
298 
299 uint16_t XCOFFObjectFile::getMagic() const {
300   return FileHdrPtr->Magic;
301 }
302 
303 uint16_t XCOFFObjectFile::getNumberOfSections() const {
304   return FileHdrPtr->NumberOfSections;
305 }
306 
307 int32_t XCOFFObjectFile::getTimeStamp() const {
308   return FileHdrPtr->TimeStamp;
309 }
310 
311 uint32_t XCOFFObjectFile::getSymbolTableOffset() const {
312   return FileHdrPtr->SymbolTableOffset;
313 }
314 
315 int32_t XCOFFObjectFile::getNumberOfSymbolTableEntries() const {
316   // As far as symbol table size is concerned, if this field is negative it is
317   // to be treated as a 0. However since this field is also used for printing we
318   // don't want to truncate any negative values.
319   return FileHdrPtr->NumberOfSymTableEntries;
320 }
321 
322 uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {
323   return FileHdrPtr->AuxHeaderSize;
324 }
325 
326 uint16_t XCOFFObjectFile::getFlags() const {
327   return FileHdrPtr->Flags;
328 }
329 
330 Expected<std::unique_ptr<ObjectFile>>
331 ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object) {
332   StringRef Data = Object.getBuffer();
333   file_magic Type = identify_magic(Data);
334   std::error_code EC;
335   std::unique_ptr<ObjectFile> Ret;
336 
337   if (Type == file_magic::xcoff_object_32) {
338     Ret.reset(new XCOFFObjectFile(Object, EC));
339   } else {
340     llvm_unreachable("Encountered an unexpected binary file type!");
341   }
342 
343   if (EC)
344     return errorCodeToError(EC);
345   return std::move(Ret);
346 }
347 
348 } // namespace object
349 } // namespace llvm
350