RuntimeDyldMachOI386.h revision 353358
1153323Srodrigc//===---- RuntimeDyldMachOI386.h ---- MachO/I386 specific code. ---*- C++ -*-=//
2159451Srodrigc//
3159451Srodrigc// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4153323Srodrigc// See https://llvm.org/LICENSE.txt for license information.
5159451Srodrigc// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6159451Srodrigc//
7153323Srodrigc//===----------------------------------------------------------------------===//
8153323Srodrigc
9159451Srodrigc#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H
10159451Srodrigc#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H
11159451Srodrigc
12159451Srodrigc#include "../RuntimeDyldMachO.h"
13153323Srodrigc#include <string>
14159451Srodrigc
15159451Srodrigc#define DEBUG_TYPE "dyld"
16159451Srodrigc
17153323Srodrigcnamespace llvm {
18153323Srodrigc
19153323Srodrigcclass RuntimeDyldMachOI386
20153323Srodrigc    : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOI386> {
21153323Srodrigcpublic:
22153323Srodrigc
23153323Srodrigc  typedef uint32_t TargetPtrT;
24153323Srodrigc
25153323Srodrigc  RuntimeDyldMachOI386(RuntimeDyld::MemoryManager &MM,
26153323Srodrigc                       JITSymbolResolver &Resolver)
27153323Srodrigc      : RuntimeDyldMachOCRTPBase(MM, Resolver) {}
28153323Srodrigc
29153323Srodrigc  unsigned getMaxStubSize() const override { return 0; }
30153323Srodrigc
31153323Srodrigc  unsigned getStubAlignment() override { return 1; }
32153323Srodrigc
33153323Srodrigc  Expected<relocation_iterator>
34153323Srodrigc  processRelocationRef(unsigned SectionID, relocation_iterator RelI,
35153323Srodrigc                       const ObjectFile &BaseObjT,
36153323Srodrigc                       ObjSectionToIDMap &ObjSectionToID,
37153323Srodrigc                       StubMap &Stubs) override {
38153323Srodrigc    const MachOObjectFile &Obj =
39153323Srodrigc        static_cast<const MachOObjectFile &>(BaseObjT);
40153323Srodrigc    MachO::any_relocation_info RelInfo =
41153323Srodrigc        Obj.getRelocation(RelI->getRawDataRefImpl());
42153323Srodrigc    uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
43153323Srodrigc
44153323Srodrigc    if (Obj.isRelocationScattered(RelInfo)) {
45153323Srodrigc      if (RelType == MachO::GENERIC_RELOC_SECTDIFF ||
46153323Srodrigc          RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)
47153323Srodrigc        return processSECTDIFFRelocation(SectionID, RelI, Obj,
48153323Srodrigc                                         ObjSectionToID);
49153323Srodrigc      else if (RelType == MachO::GENERIC_RELOC_VANILLA)
50153323Srodrigc        return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID);
51153323Srodrigc      return make_error<RuntimeDyldError>(("Unhandled I386 scattered relocation "
52153323Srodrigc                                           "type: " + Twine(RelType)).str());
53153323Srodrigc    }
54153323Srodrigc
55153323Srodrigc    switch (RelType) {
56153323Srodrigc    UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_PAIR);
57153323Srodrigc    UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_PB_LA_PTR);
58153323Srodrigc    UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_TLV);
59153323Srodrigc    default:
60153323Srodrigc      if (RelType > MachO::GENERIC_RELOC_TLV)
61153323Srodrigc        return make_error<RuntimeDyldError>(("MachO I386 relocation type " +
62153323Srodrigc                                             Twine(RelType) +
63153323Srodrigc                                             " is out of range").str());
64153323Srodrigc      break;
65153323Srodrigc    }
66153323Srodrigc
67153323Srodrigc    RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
68153323Srodrigc    RE.Addend = memcpyAddend(RE);
69153323Srodrigc    RelocationValueRef Value;
70153323Srodrigc    if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
71153323Srodrigc      Value = *ValueOrErr;
72153323Srodrigc    else
73153323Srodrigc      return ValueOrErr.takeError();
74153323Srodrigc
75153323Srodrigc    // Addends for external, PC-rel relocations on i386 point back to the zero
76153323Srodrigc    // offset. Calculate the final offset from the relocation target instead.
77153323Srodrigc    // This allows us to use the same logic for both external and internal
78153323Srodrigc    // relocations in resolveI386RelocationRef.
79153323Srodrigc    // bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
80153323Srodrigc    // if (IsExtern && RE.IsPCRel) {
81153323Srodrigc    //   uint64_t RelocAddr = 0;
82153323Srodrigc    //   RelI->getAddress(RelocAddr);
83153323Srodrigc    //   Value.Addend += RelocAddr + 4;
84153323Srodrigc    // }
85153323Srodrigc    if (RE.IsPCRel)
86153323Srodrigc      makeValueAddendPCRel(Value, RelI, 1 << RE.Size);
87153323Srodrigc
88153323Srodrigc    RE.Addend = Value.Offset;
89153323Srodrigc
90153323Srodrigc    if (Value.SymbolName)
91153323Srodrigc      addRelocationForSymbol(RE, Value.SymbolName);
92153323Srodrigc    else
93153323Srodrigc      addRelocationForSection(RE, Value.SectionID);
94153323Srodrigc
95153323Srodrigc    return ++RelI;
96153323Srodrigc  }
97153323Srodrigc
98153323Srodrigc  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
99153323Srodrigc    LLVM_DEBUG(dumpRelocationToResolve(RE, Value));
100153323Srodrigc
101153323Srodrigc    const SectionEntry &Section = Sections[RE.SectionID];
102153323Srodrigc    uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
103153323Srodrigc
104153323Srodrigc    if (RE.IsPCRel) {
105153323Srodrigc      uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
106153323Srodrigc      Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation.
107159451Srodrigc    }
108159451Srodrigc
109153323Srodrigc    switch (RE.RelType) {
110153323Srodrigc    case MachO::GENERIC_RELOC_VANILLA:
111153323Srodrigc      writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
112      break;
113    case MachO::GENERIC_RELOC_SECTDIFF:
114    case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
115      uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
116      uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
117      assert((Value == SectionABase || Value == SectionBBase) &&
118             "Unexpected SECTDIFF relocation value.");
119      Value = SectionABase - SectionBBase + RE.Addend;
120      writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size);
121      break;
122    }
123    default:
124      llvm_unreachable("Invalid relocation type!");
125    }
126  }
127
128  Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
129                       const SectionRef &Section) {
130    StringRef Name;
131    Section.getName(Name);
132
133    if (Name == "__jump_table")
134      return populateJumpTable(cast<MachOObjectFile>(Obj), Section, SectionID);
135    else if (Name == "__pointers")
136      return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj),
137                                                   Section, SectionID);
138    return Error::success();
139  }
140
141private:
142  Expected<relocation_iterator>
143  processSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,
144                            const ObjectFile &BaseObjT,
145                            ObjSectionToIDMap &ObjSectionToID) {
146    const MachOObjectFile &Obj =
147        static_cast<const MachOObjectFile&>(BaseObjT);
148    MachO::any_relocation_info RE =
149        Obj.getRelocation(RelI->getRawDataRefImpl());
150
151    SectionEntry &Section = Sections[SectionID];
152    uint32_t RelocType = Obj.getAnyRelocationType(RE);
153    bool IsPCRel = Obj.getAnyRelocationPCRel(RE);
154    unsigned Size = Obj.getAnyRelocationLength(RE);
155    uint64_t Offset = RelI->getOffset();
156    uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);
157    unsigned NumBytes = 1 << Size;
158    uint64_t Addend = readBytesUnaligned(LocalAddress, NumBytes);
159
160    ++RelI;
161    MachO::any_relocation_info RE2 =
162        Obj.getRelocation(RelI->getRawDataRefImpl());
163
164    uint32_t AddrA = Obj.getScatteredRelocationValue(RE);
165    section_iterator SAI = getSectionByAddress(Obj, AddrA);
166    assert(SAI != Obj.section_end() && "Can't find section for address A");
167    uint64_t SectionABase = SAI->getAddress();
168    uint64_t SectionAOffset = AddrA - SectionABase;
169    SectionRef SectionA = *SAI;
170    bool IsCode = SectionA.isText();
171    uint32_t SectionAID = ~0U;
172    if (auto SectionAIDOrErr =
173        findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID))
174      SectionAID = *SectionAIDOrErr;
175    else
176      return SectionAIDOrErr.takeError();
177
178    uint32_t AddrB = Obj.getScatteredRelocationValue(RE2);
179    section_iterator SBI = getSectionByAddress(Obj, AddrB);
180    assert(SBI != Obj.section_end() && "Can't find section for address B");
181    uint64_t SectionBBase = SBI->getAddress();
182    uint64_t SectionBOffset = AddrB - SectionBBase;
183    SectionRef SectionB = *SBI;
184    uint32_t SectionBID = ~0U;
185    if (auto SectionBIDOrErr =
186        findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID))
187      SectionBID = *SectionBIDOrErr;
188    else
189      return SectionBIDOrErr.takeError();
190
191    // Compute the addend 'C' from the original expression 'A - B + C'.
192    Addend -= AddrA - AddrB;
193
194    LLVM_DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA
195                      << ", AddrB: " << AddrB << ", Addend: " << Addend
196                      << ", SectionA ID: " << SectionAID << ", SectionAOffset: "
197                      << SectionAOffset << ", SectionB ID: " << SectionBID
198                      << ", SectionBOffset: " << SectionBOffset << "\n");
199    RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,
200                      SectionAOffset, SectionBID, SectionBOffset,
201                      IsPCRel, Size);
202
203    addRelocationForSection(R, SectionAID);
204
205    return ++RelI;
206  }
207
208  // Populate stubs in __jump_table section.
209  Error populateJumpTable(const MachOObjectFile &Obj,
210                          const SectionRef &JTSection,
211                         unsigned JTSectionID) {
212    MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
213    MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl());
214    uint32_t JTSectionSize = Sec32.size;
215    unsigned FirstIndirectSymbol = Sec32.reserved1;
216    unsigned JTEntrySize = Sec32.reserved2;
217    unsigned NumJTEntries = JTSectionSize / JTEntrySize;
218    uint8_t *JTSectionAddr = getSectionAddress(JTSectionID);
219    unsigned JTEntryOffset = 0;
220
221    if (JTSectionSize % JTEntrySize != 0)
222      return make_error<RuntimeDyldError>("Jump-table section does not contain "
223                                          "a whole number of stubs?");
224
225    for (unsigned i = 0; i < NumJTEntries; ++i) {
226      unsigned SymbolIndex =
227          Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
228      symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
229      Expected<StringRef> IndirectSymbolName = SI->getName();
230      if (!IndirectSymbolName)
231        return IndirectSymbolName.takeError();
232      uint8_t *JTEntryAddr = JTSectionAddr + JTEntryOffset;
233      createStubFunction(JTEntryAddr);
234      RelocationEntry RE(JTSectionID, JTEntryOffset + 1,
235                         MachO::GENERIC_RELOC_VANILLA, 0, true, 2);
236      addRelocationForSymbol(RE, *IndirectSymbolName);
237      JTEntryOffset += JTEntrySize;
238    }
239
240    return Error::success();
241  }
242
243};
244}
245
246#undef DEBUG_TYPE
247
248#endif
249