xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===--- RuntimeDyldCOFFI386.h --- COFF/X86_64 specific code ---*- C++ --*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // COFF x86 support for MC-JIT runtime dynamic linker.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H
140b57cec5SDimitry Andric #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "../RuntimeDyldCOFF.h"
170b57cec5SDimitry Andric #include "llvm/BinaryFormat/COFF.h"
180b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #define DEBUG_TYPE "dyld"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace llvm {
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF {
250b57cec5SDimitry Andric public:
260b57cec5SDimitry Andric   RuntimeDyldCOFFI386(RuntimeDyld::MemoryManager &MM,
270b57cec5SDimitry Andric                       JITSymbolResolver &Resolver)
285ffd83dbSDimitry Andric       : RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_I386_DIR32) {}
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric   unsigned getMaxStubSize() const override {
310b57cec5SDimitry Andric     return 8; // 2-byte jmp instruction + 32-bit relative address + 2 byte pad
320b57cec5SDimitry Andric   }
330b57cec5SDimitry Andric 
34bdd1243dSDimitry Andric   Align getStubAlignment() override { return Align(1); }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   Expected<object::relocation_iterator>
370b57cec5SDimitry Andric   processRelocationRef(unsigned SectionID,
380b57cec5SDimitry Andric                        object::relocation_iterator RelI,
390b57cec5SDimitry Andric                        const object::ObjectFile &Obj,
400b57cec5SDimitry Andric                        ObjSectionToIDMap &ObjSectionToID,
410b57cec5SDimitry Andric                        StubMap &Stubs) override {
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric     auto Symbol = RelI->getSymbol();
440b57cec5SDimitry Andric     if (Symbol == Obj.symbol_end())
450b57cec5SDimitry Andric       report_fatal_error("Unknown symbol in relocation");
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric     Expected<StringRef> TargetNameOrErr = Symbol->getName();
480b57cec5SDimitry Andric     if (!TargetNameOrErr)
490b57cec5SDimitry Andric       return TargetNameOrErr.takeError();
500b57cec5SDimitry Andric     StringRef TargetName = *TargetNameOrErr;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric     auto SectionOrErr = Symbol->getSection();
530b57cec5SDimitry Andric     if (!SectionOrErr)
540b57cec5SDimitry Andric       return SectionOrErr.takeError();
550b57cec5SDimitry Andric     auto Section = *SectionOrErr;
565ffd83dbSDimitry Andric     bool IsExtern = Section == Obj.section_end();
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric     uint64_t RelType = RelI->getType();
590b57cec5SDimitry Andric     uint64_t Offset = RelI->getOffset();
600b57cec5SDimitry Andric 
615ffd83dbSDimitry Andric     unsigned TargetSectionID = -1;
625ffd83dbSDimitry Andric     uint64_t TargetOffset = -1;
63*5f757f3fSDimitry Andric     if (TargetName.starts_with(getImportSymbolPrefix())) {
645ffd83dbSDimitry Andric       TargetSectionID = SectionID;
655ffd83dbSDimitry Andric       TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);
665ffd83dbSDimitry Andric       TargetName = StringRef();
675ffd83dbSDimitry Andric       IsExtern = false;
685ffd83dbSDimitry Andric     } else if (!IsExtern) {
695ffd83dbSDimitry Andric       if (auto TargetSectionIDOrErr = findOrEmitSection(
705ffd83dbSDimitry Andric               Obj, *Section, Section->isText(), ObjSectionToID))
715ffd83dbSDimitry Andric         TargetSectionID = *TargetSectionIDOrErr;
725ffd83dbSDimitry Andric       else
735ffd83dbSDimitry Andric         return TargetSectionIDOrErr.takeError();
745ffd83dbSDimitry Andric       if (RelType != COFF::IMAGE_REL_I386_SECTION)
755ffd83dbSDimitry Andric         TargetOffset = getSymbolOffset(*Symbol);
765ffd83dbSDimitry Andric     }
775ffd83dbSDimitry Andric 
780b57cec5SDimitry Andric     // Determine the Addend used to adjust the relocation value.
790b57cec5SDimitry Andric     uint64_t Addend = 0;
800b57cec5SDimitry Andric     SectionEntry &AddendSection = Sections[SectionID];
810b57cec5SDimitry Andric     uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
820b57cec5SDimitry Andric     uint8_t *Displacement = (uint8_t *)ObjTarget;
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric     switch (RelType) {
850b57cec5SDimitry Andric     case COFF::IMAGE_REL_I386_DIR32:
860b57cec5SDimitry Andric     case COFF::IMAGE_REL_I386_DIR32NB:
870b57cec5SDimitry Andric     case COFF::IMAGE_REL_I386_SECREL:
880b57cec5SDimitry Andric     case COFF::IMAGE_REL_I386_REL32: {
890b57cec5SDimitry Andric       Addend = readBytesUnaligned(Displacement, 4);
900b57cec5SDimitry Andric       break;
910b57cec5SDimitry Andric     }
920b57cec5SDimitry Andric     default:
930b57cec5SDimitry Andric       break;
940b57cec5SDimitry Andric     }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric #if !defined(NDEBUG)
970b57cec5SDimitry Andric     SmallString<32> RelTypeName;
980b57cec5SDimitry Andric     RelI->getTypeName(RelTypeName);
990b57cec5SDimitry Andric #endif
1000b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
1010b57cec5SDimitry Andric                       << " RelType: " << RelTypeName << " TargetName: "
1020b57cec5SDimitry Andric                       << TargetName << " Addend " << Addend << "\n");
1030b57cec5SDimitry Andric 
1045ffd83dbSDimitry Andric     if (IsExtern) {
1050b57cec5SDimitry Andric       RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
1060b57cec5SDimitry Andric       addRelocationForSymbol(RE, TargetName);
1070b57cec5SDimitry Andric     } else {
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric       switch (RelType) {
1100b57cec5SDimitry Andric       case COFF::IMAGE_REL_I386_ABSOLUTE:
1110b57cec5SDimitry Andric         // This relocation is ignored.
1120b57cec5SDimitry Andric         break;
1130b57cec5SDimitry Andric       case COFF::IMAGE_REL_I386_DIR32:
1140b57cec5SDimitry Andric       case COFF::IMAGE_REL_I386_DIR32NB:
1150b57cec5SDimitry Andric       case COFF::IMAGE_REL_I386_REL32: {
1160b57cec5SDimitry Andric         RelocationEntry RE =
1170b57cec5SDimitry Andric             RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
1185ffd83dbSDimitry Andric                             TargetOffset, 0, 0, false, 0);
1190b57cec5SDimitry Andric         addRelocationForSection(RE, TargetSectionID);
1200b57cec5SDimitry Andric         break;
1210b57cec5SDimitry Andric       }
1220b57cec5SDimitry Andric       case COFF::IMAGE_REL_I386_SECTION: {
1230b57cec5SDimitry Andric         RelocationEntry RE =
1240b57cec5SDimitry Andric             RelocationEntry(TargetSectionID, Offset, RelType, 0);
1250b57cec5SDimitry Andric         addRelocationForSection(RE, TargetSectionID);
1260b57cec5SDimitry Andric         break;
1270b57cec5SDimitry Andric       }
1280b57cec5SDimitry Andric       case COFF::IMAGE_REL_I386_SECREL: {
1295ffd83dbSDimitry Andric         RelocationEntry RE =
1305ffd83dbSDimitry Andric             RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend);
1310b57cec5SDimitry Andric         addRelocationForSection(RE, TargetSectionID);
1320b57cec5SDimitry Andric         break;
1330b57cec5SDimitry Andric       }
1340b57cec5SDimitry Andric       default:
1350b57cec5SDimitry Andric         llvm_unreachable("unsupported relocation type");
1360b57cec5SDimitry Andric       }
1370b57cec5SDimitry Andric     }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric     return ++RelI;
1400b57cec5SDimitry Andric   }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
1430b57cec5SDimitry Andric     const auto Section = Sections[RE.SectionID];
1440b57cec5SDimitry Andric     uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric     switch (RE.RelType) {
1470b57cec5SDimitry Andric     case COFF::IMAGE_REL_I386_ABSOLUTE:
1480b57cec5SDimitry Andric       // This relocation is ignored.
1490b57cec5SDimitry Andric       break;
1500b57cec5SDimitry Andric     case COFF::IMAGE_REL_I386_DIR32: {
1510b57cec5SDimitry Andric       // The target's 32-bit VA.
1520b57cec5SDimitry Andric       uint64_t Result =
1530b57cec5SDimitry Andric           RE.Sections.SectionA == static_cast<uint32_t>(-1)
1540b57cec5SDimitry Andric               ? Value
1550b57cec5SDimitry Andric               : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(
1560b57cec5SDimitry Andric                     RE.Addend);
1570b57cec5SDimitry Andric       assert(Result <= UINT32_MAX && "relocation overflow");
1580b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
1590b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_I386_DIR32"
1600b57cec5SDimitry Andric                         << " TargetSection: " << RE.Sections.SectionA
1610b57cec5SDimitry Andric                         << " Value: " << format("0x%08" PRIx32, Result)
1620b57cec5SDimitry Andric                         << '\n');
1630b57cec5SDimitry Andric       writeBytesUnaligned(Result, Target, 4);
1640b57cec5SDimitry Andric       break;
1650b57cec5SDimitry Andric     }
1660b57cec5SDimitry Andric     case COFF::IMAGE_REL_I386_DIR32NB: {
1670b57cec5SDimitry Andric       // The target's 32-bit RVA.
1680b57cec5SDimitry Andric       // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
1690b57cec5SDimitry Andric       uint64_t Result =
1700b57cec5SDimitry Andric           Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend) -
1710b57cec5SDimitry Andric           Sections[0].getLoadAddress();
1720b57cec5SDimitry Andric       assert(Result <= UINT32_MAX && "relocation overflow");
1730b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
1740b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_I386_DIR32NB"
1750b57cec5SDimitry Andric                         << " TargetSection: " << RE.Sections.SectionA
1760b57cec5SDimitry Andric                         << " Value: " << format("0x%08" PRIx32, Result)
1770b57cec5SDimitry Andric                         << '\n');
1780b57cec5SDimitry Andric       writeBytesUnaligned(Result, Target, 4);
1790b57cec5SDimitry Andric       break;
1800b57cec5SDimitry Andric     }
1810b57cec5SDimitry Andric     case COFF::IMAGE_REL_I386_REL32: {
1820b57cec5SDimitry Andric       // 32-bit relative displacement to the target.
1830b57cec5SDimitry Andric       uint64_t Result = RE.Sections.SectionA == static_cast<uint32_t>(-1)
1840b57cec5SDimitry Andric                             ? Value
1850b57cec5SDimitry Andric                             : Sections[RE.Sections.SectionA].getLoadAddress();
1860b57cec5SDimitry Andric       Result = Result - Section.getLoadAddress() + RE.Addend - 4 - RE.Offset;
1870b57cec5SDimitry Andric       assert(static_cast<int64_t>(Result) <= INT32_MAX &&
1880b57cec5SDimitry Andric              "relocation overflow");
1890b57cec5SDimitry Andric       assert(static_cast<int64_t>(Result) >= INT32_MIN &&
1900b57cec5SDimitry Andric              "relocation underflow");
1910b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
1920b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_I386_REL32"
1930b57cec5SDimitry Andric                         << " TargetSection: " << RE.Sections.SectionA
1940b57cec5SDimitry Andric                         << " Value: " << format("0x%08" PRIx32, Result)
1950b57cec5SDimitry Andric                         << '\n');
1960b57cec5SDimitry Andric       writeBytesUnaligned(Result, Target, 4);
1970b57cec5SDimitry Andric       break;
1980b57cec5SDimitry Andric     }
1990b57cec5SDimitry Andric     case COFF::IMAGE_REL_I386_SECTION:
2000b57cec5SDimitry Andric       // 16-bit section index of the section that contains the target.
2010b57cec5SDimitry Andric       assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
2020b57cec5SDimitry Andric              "relocation overflow");
2030b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
2040b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_I386_SECTION Value: "
2050b57cec5SDimitry Andric                         << RE.SectionID << '\n');
2060b57cec5SDimitry Andric       writeBytesUnaligned(RE.SectionID, Target, 2);
2070b57cec5SDimitry Andric       break;
2080b57cec5SDimitry Andric     case COFF::IMAGE_REL_I386_SECREL:
2090b57cec5SDimitry Andric       // 32-bit offset of the target from the beginning of its section.
2100b57cec5SDimitry Andric       assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
2110b57cec5SDimitry Andric              "relocation overflow");
2120b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
2130b57cec5SDimitry Andric                         << " RelType: IMAGE_REL_I386_SECREL Value: "
2140b57cec5SDimitry Andric                         << RE.Addend << '\n');
2150b57cec5SDimitry Andric       writeBytesUnaligned(RE.Addend, Target, 4);
2160b57cec5SDimitry Andric       break;
2170b57cec5SDimitry Andric     default:
2180b57cec5SDimitry Andric       llvm_unreachable("unsupported relocation type");
2190b57cec5SDimitry Andric     }
2200b57cec5SDimitry Andric   }
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric   void registerEHFrames() override {}
2230b57cec5SDimitry Andric };
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric #endif
2280b57cec5SDimitry Andric 
229