xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp (revision b3551da9cd3dacbc7242c3be6fefe234784645fe)
1  //===------ ObjectFileInterface.cpp - MU interface utils for objects ------===//
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  #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
10  #include "llvm/ExecutionEngine/Orc/COFFPlatform.h"
11  #include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
12  #include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
13  #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h"
14  #include "llvm/Object/COFF.h"
15  #include "llvm/Object/ELFObjectFile.h"
16  #include "llvm/Object/MachO.h"
17  #include "llvm/Object/ObjectFile.h"
18  #include "llvm/Support/Debug.h"
19  #include <optional>
20  
21  #define DEBUG_TYPE "orc"
22  
23  namespace llvm {
24  namespace orc {
25  
26  void addInitSymbol(MaterializationUnit::Interface &I, ExecutionSession &ES,
27                     StringRef ObjFileName) {
28    assert(!I.InitSymbol && "I already has an init symbol");
29    size_t Counter = 0;
30  
31    do {
32      std::string InitSymString;
33      raw_string_ostream(InitSymString)
34          << "$." << ObjFileName << ".__inits." << Counter++;
35      I.InitSymbol = ES.intern(InitSymString);
36    } while (I.SymbolFlags.count(I.InitSymbol));
37  
38    I.SymbolFlags[I.InitSymbol] = JITSymbolFlags::MaterializationSideEffectsOnly;
39  }
40  
41  static Expected<MaterializationUnit::Interface>
42  getMachOObjectFileSymbolInfo(ExecutionSession &ES,
43                               const object::MachOObjectFile &Obj) {
44    MaterializationUnit::Interface I;
45  
46    for (auto &Sym : Obj.symbols()) {
47      Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
48      if (!SymFlagsOrErr)
49        // TODO: Test this error.
50        return SymFlagsOrErr.takeError();
51  
52      // Skip symbols not defined in this object file.
53      if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)
54        continue;
55  
56      // Skip symbols that are not global.
57      if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global))
58        continue;
59  
60      // Skip symbols that have type SF_File.
61      if (auto SymType = Sym.getType()) {
62        if (*SymType == object::SymbolRef::ST_File)
63          continue;
64      } else
65        return SymType.takeError();
66  
67      auto Name = Sym.getName();
68      if (!Name)
69        return Name.takeError();
70      auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
71      if (!SymFlags)
72        return SymFlags.takeError();
73  
74      // Strip the 'exported' flag from MachO linker-private symbols.
75      if (Name->starts_with("l"))
76        *SymFlags &= ~JITSymbolFlags::Exported;
77  
78      I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags);
79    }
80  
81    for (auto &Sec : Obj.sections()) {
82      auto SecType = Obj.getSectionType(Sec);
83      if ((SecType & MachO::SECTION_TYPE) == MachO::S_MOD_INIT_FUNC_POINTERS) {
84        addInitSymbol(I, ES, Obj.getFileName());
85        break;
86      }
87      auto SegName = Obj.getSectionFinalSegmentName(Sec.getRawDataRefImpl());
88      auto SecName = cantFail(Obj.getSectionName(Sec.getRawDataRefImpl()));
89      if (isMachOInitializerSection(SegName, SecName)) {
90        addInitSymbol(I, ES, Obj.getFileName());
91        break;
92      }
93    }
94  
95    return I;
96  }
97  
98  static Expected<MaterializationUnit::Interface>
99  getELFObjectFileSymbolInfo(ExecutionSession &ES,
100                             const object::ELFObjectFileBase &Obj) {
101    MaterializationUnit::Interface I;
102  
103    for (auto &Sym : Obj.symbols()) {
104      Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
105      if (!SymFlagsOrErr)
106        // TODO: Test this error.
107        return SymFlagsOrErr.takeError();
108  
109      // Skip symbols not defined in this object file.
110      if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)
111        continue;
112  
113      // Skip symbols that are not global.
114      if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global))
115        continue;
116  
117      // Skip symbols that have type SF_File.
118      if (auto SymType = Sym.getType()) {
119        if (*SymType == object::SymbolRef::ST_File)
120          continue;
121      } else
122        return SymType.takeError();
123  
124      auto Name = Sym.getName();
125      if (!Name)
126        return Name.takeError();
127  
128      auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
129      if (!SymFlags)
130        return SymFlags.takeError();
131  
132      // ELF STB_GNU_UNIQUE should map to Weak for ORC.
133      if (Sym.getBinding() == ELF::STB_GNU_UNIQUE)
134        *SymFlags |= JITSymbolFlags::Weak;
135  
136      I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags);
137    }
138  
139    SymbolStringPtr InitSymbol;
140    for (auto &Sec : Obj.sections()) {
141      if (auto SecName = Sec.getName()) {
142        if (isELFInitializerSection(*SecName)) {
143          addInitSymbol(I, ES, Obj.getFileName());
144          break;
145        }
146      }
147    }
148  
149    return I;
150  }
151  
152  static Expected<MaterializationUnit::Interface>
153  getCOFFObjectFileSymbolInfo(ExecutionSession &ES,
154                              const object::COFFObjectFile &Obj) {
155    MaterializationUnit::Interface I;
156    std::vector<std::optional<object::coff_aux_section_definition>> ComdatDefs(
157        Obj.getNumberOfSections() + 1);
158    for (auto &Sym : Obj.symbols()) {
159      Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
160      if (!SymFlagsOrErr)
161        // TODO: Test this error.
162        return SymFlagsOrErr.takeError();
163  
164      // Handle comdat symbols
165      auto COFFSym = Obj.getCOFFSymbol(Sym);
166      bool IsWeak = false;
167      if (auto *Def = COFFSym.getSectionDefinition()) {
168        auto Sec = Obj.getSection(COFFSym.getSectionNumber());
169        if (!Sec)
170          return Sec.takeError();
171        if (((*Sec)->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT) &&
172            Def->Selection != COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
173          ComdatDefs[COFFSym.getSectionNumber()] = *Def;
174          continue;
175        }
176      }
177      if (!COFF::isReservedSectionNumber(COFFSym.getSectionNumber()) &&
178          ComdatDefs[COFFSym.getSectionNumber()]) {
179        auto Def = ComdatDefs[COFFSym.getSectionNumber()];
180        if (Def->Selection != COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) {
181          IsWeak = true;
182        }
183        ComdatDefs[COFFSym.getSectionNumber()] = std::nullopt;
184      } else {
185        // Skip symbols not defined in this object file.
186        if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)
187          continue;
188      }
189  
190      // Skip symbols that are not global.
191      if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global))
192        continue;
193  
194      // Skip symbols that have type SF_File.
195      if (auto SymType = Sym.getType()) {
196        if (*SymType == object::SymbolRef::ST_File)
197          continue;
198      } else
199        return SymType.takeError();
200  
201      auto Name = Sym.getName();
202      if (!Name)
203        return Name.takeError();
204  
205      auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
206      if (!SymFlags)
207        return SymFlags.takeError();
208      *SymFlags |= JITSymbolFlags::Exported;
209  
210      // Weak external is always a function
211      if (COFFSym.isWeakExternal())
212        *SymFlags |= JITSymbolFlags::Callable;
213  
214      if (IsWeak)
215        *SymFlags |= JITSymbolFlags::Weak;
216  
217      I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags);
218    }
219  
220    SymbolStringPtr InitSymbol;
221    for (auto &Sec : Obj.sections()) {
222      if (auto SecName = Sec.getName()) {
223        if (isCOFFInitializerSection(*SecName)) {
224          addInitSymbol(I, ES, Obj.getFileName());
225          break;
226        }
227      } else
228        return SecName.takeError();
229    }
230  
231    return I;
232  }
233  
234  Expected<MaterializationUnit::Interface>
235  getGenericObjectFileSymbolInfo(ExecutionSession &ES,
236                                 const object::ObjectFile &Obj) {
237    MaterializationUnit::Interface I;
238  
239    for (auto &Sym : Obj.symbols()) {
240      Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
241      if (!SymFlagsOrErr)
242        // TODO: Test this error.
243        return SymFlagsOrErr.takeError();
244  
245      // Skip symbols not defined in this object file.
246      if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)
247        continue;
248  
249      // Skip symbols that are not global.
250      if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global))
251        continue;
252  
253      // Skip symbols that have type SF_File.
254      if (auto SymType = Sym.getType()) {
255        if (*SymType == object::SymbolRef::ST_File)
256          continue;
257      } else
258        return SymType.takeError();
259  
260      auto Name = Sym.getName();
261      if (!Name)
262        return Name.takeError();
263  
264      auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
265      if (!SymFlags)
266        return SymFlags.takeError();
267  
268      I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags);
269    }
270  
271    return I;
272  }
273  
274  Expected<MaterializationUnit::Interface>
275  getObjectFileInterface(ExecutionSession &ES, MemoryBufferRef ObjBuffer) {
276    auto Obj = object::ObjectFile::createObjectFile(ObjBuffer);
277  
278    if (!Obj)
279      return Obj.takeError();
280  
281    if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(Obj->get()))
282      return getMachOObjectFileSymbolInfo(ES, *MachOObj);
283    else if (auto *ELFObj = dyn_cast<object::ELFObjectFileBase>(Obj->get()))
284      return getELFObjectFileSymbolInfo(ES, *ELFObj);
285    else if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj->get()))
286      return getCOFFObjectFileSymbolInfo(ES, *COFFObj);
287  
288    return getGenericObjectFileSymbolInfo(ES, **Obj);
289  }
290  
291  } // End namespace orc.
292  } // End namespace llvm.
293