xref: /llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp (revision e1cb2c0f404d9fe68f5f465a281be295ca24ec33)
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 Expected<ArrayRef<uint8_t>>
141 XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
142   llvm_unreachable("Not yet implemented!");
143 }
144 
145 uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
146   uint64_t Result = 0;
147   llvm_unreachable("Not yet implemented!");
148   return Result;
149 }
150 
151 bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
152   bool Result = false;
153   llvm_unreachable("Not yet implemented!");
154   return Result;
155 }
156 
157 bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {
158   return toSection(Sec)->Flags & XCOFF::STYP_TEXT;
159 }
160 
161 bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {
162   unsigned Flags = toSection(Sec)->Flags;
163   return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);
164 }
165 
166 bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {
167   unsigned Flags = toSection(Sec)->Flags;
168   return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);
169 }
170 
171 bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {
172   bool Result = false;
173   llvm_unreachable("Not yet implemented!");
174   return Result;
175 }
176 
177 relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {
178   llvm_unreachable("Not yet implemented!");
179   return relocation_iterator(RelocationRef());
180 }
181 
182 relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const {
183   llvm_unreachable("Not yet implemented!");
184   return relocation_iterator(RelocationRef());
185 }
186 
187 void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
188   llvm_unreachable("Not yet implemented!");
189   return;
190 }
191 
192 uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
193   llvm_unreachable("Not yet implemented!");
194   uint64_t Result = 0;
195   return Result;
196 }
197 
198 symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
199   llvm_unreachable("Not yet implemented!");
200   return symbol_iterator(SymbolRef());
201 }
202 
203 uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
204   llvm_unreachable("Not yet implemented!");
205   uint64_t Result = 0;
206   return Result;
207 }
208 
209 void XCOFFObjectFile::getRelocationTypeName(
210     DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
211   llvm_unreachable("Not yet implemented!");
212   return;
213 }
214 
215 uint32_t XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
216   uint32_t Result = 0;
217   llvm_unreachable("Not yet implemented!");
218   return Result;
219 }
220 
221 basic_symbol_iterator XCOFFObjectFile::symbol_begin() const {
222   llvm_unreachable("Not yet implemented!");
223   return basic_symbol_iterator(SymbolRef());
224 }
225 
226 basic_symbol_iterator XCOFFObjectFile::symbol_end() const {
227   llvm_unreachable("Not yet implemented!");
228   return basic_symbol_iterator(SymbolRef());
229 }
230 
231 section_iterator XCOFFObjectFile::section_begin() const {
232   DataRefImpl DRI;
233   DRI.p = reinterpret_cast<uintptr_t>(SectionHdrTablePtr);
234   return section_iterator(SectionRef(DRI, this));
235 }
236 
237 section_iterator XCOFFObjectFile::section_end() const {
238   DataRefImpl DRI;
239   DRI.p =
240       reinterpret_cast<uintptr_t>(SectionHdrTablePtr + getNumberOfSections());
241   return section_iterator(SectionRef(DRI, this));
242 }
243 
244 uint8_t XCOFFObjectFile::getBytesInAddress() const {
245   // Only support 32-bit object files for now ...
246   assert(getFileHeaderSize() ==  XCOFF32FileHeaderSize);
247   return 4;
248 }
249 
250 StringRef XCOFFObjectFile::getFileFormatName() const {
251   assert(getFileHeaderSize() == XCOFF32FileHeaderSize);
252   return "aixcoff-rs6000";
253 }
254 
255 Triple::ArchType XCOFFObjectFile::getArch() const {
256   assert(getFileHeaderSize() == XCOFF32FileHeaderSize);
257   return Triple::ppc;
258 }
259 
260 SubtargetFeatures XCOFFObjectFile::getFeatures() const {
261   llvm_unreachable("Not yet implemented!");
262   return SubtargetFeatures();
263 }
264 
265 bool XCOFFObjectFile::isRelocatableObject() const {
266   bool Result = false;
267   llvm_unreachable("Not yet implemented!");
268   return Result;
269 }
270 
271 Expected<uint64_t> XCOFFObjectFile::getStartAddress() const {
272   // TODO FIXME Should get from auxiliary_header->o_entry when support for the
273   // auxiliary_header is added.
274   return 0;
275 }
276 
277 XCOFFObjectFile::XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
278     : ObjectFile(Binary::ID_XCOFF32, Object) {
279 
280   // Current location within the file.
281   uint64_t CurPtr = 0;
282 
283   if ((EC = getObject(FileHdrPtr, Data, base() + CurPtr)))
284     return;
285 
286   CurPtr += getFileHeaderSize();
287   // TODO FIXME we don't have support for an optional header yet, so just skip
288   // past it.
289   CurPtr += FileHdrPtr->AuxHeaderSize;
290 
291   if (getNumberOfSections() != 0) {
292     if ((EC = getObject(SectionHdrTablePtr, Data, base() + CurPtr,
293                         getNumberOfSections() * getSectionHeaderSize())))
294       return;
295   }
296 }
297 
298 uint16_t XCOFFObjectFile::getMagic() const {
299   return FileHdrPtr->Magic;
300 }
301 
302 uint16_t XCOFFObjectFile::getNumberOfSections() const {
303   return FileHdrPtr->NumberOfSections;
304 }
305 
306 int32_t XCOFFObjectFile::getTimeStamp() const {
307   return FileHdrPtr->TimeStamp;
308 }
309 
310 uint32_t XCOFFObjectFile::getSymbolTableOffset() const {
311   return FileHdrPtr->SymbolTableOffset;
312 }
313 
314 int32_t XCOFFObjectFile::getNumberOfSymbolTableEntries() const {
315   // As far as symbol table size is concerned, if this field is negative it is
316   // to be treated as a 0. However since this field is also used for printing we
317   // don't want to truncate any negative values.
318   return FileHdrPtr->NumberOfSymTableEntries;
319 }
320 
321 uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {
322   return FileHdrPtr->AuxHeaderSize;
323 }
324 
325 uint16_t XCOFFObjectFile::getFlags() const {
326   return FileHdrPtr->Flags;
327 }
328 
329 Expected<std::unique_ptr<ObjectFile>>
330 ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object) {
331   StringRef Data = Object.getBuffer();
332   file_magic Type = identify_magic(Data);
333   std::error_code EC;
334   std::unique_ptr<ObjectFile> Ret;
335 
336   if (Type == file_magic::xcoff_object_32) {
337     Ret.reset(new XCOFFObjectFile(Object, EC));
338   } else {
339     llvm_unreachable("Encountered an unexpected binary file type!");
340   }
341 
342   if (EC)
343     return errorCodeToError(EC);
344   return std::move(Ret);
345 }
346 
347 } // namespace object
348 } // namespace llvm
349