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