Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h
35294 views
//===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// COFF thumb support for MC-JIT runtime dynamic linker.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H13#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H1415#include "../RuntimeDyldCOFF.h"16#include "llvm/ADT/SmallString.h"17#include "llvm/BinaryFormat/COFF.h"18#include "llvm/Object/COFF.h"1920#define DEBUG_TYPE "dyld"2122namespace llvm {2324static bool isThumbFunc(object::symbol_iterator Symbol,25const object::ObjectFile &Obj,26object::section_iterator Section) {27Expected<object::SymbolRef::Type> SymTypeOrErr = Symbol->getType();28if (!SymTypeOrErr) {29std::string Buf;30raw_string_ostream OS(Buf);31logAllUnhandledErrors(SymTypeOrErr.takeError(), OS);32report_fatal_error(Twine(OS.str()));33}3435if (*SymTypeOrErr != object::SymbolRef::ST_Function)36return false;3738// We check the IMAGE_SCN_MEM_16BIT flag in the section of the symbol to tell39// if it's thumb or not40return cast<object::COFFObjectFile>(Obj)41.getCOFFSection(*Section)42->Characteristics &43COFF::IMAGE_SCN_MEM_16BIT;44}4546class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {47public:48RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,49JITSymbolResolver &Resolver)50: RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_ARM_ADDR32) {}5152unsigned getMaxStubSize() const override {53return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding54}5556Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &SR) override {5758auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR);5960if (!Flags) {61return Flags.takeError();62}63auto SectionIterOrErr = SR.getSection();64if (!SectionIterOrErr) {65return SectionIterOrErr.takeError();66}67SectionRef Sec = *SectionIterOrErr.get();68const object::COFFObjectFile *COFFObjPtr =69cast<object::COFFObjectFile>(Sec.getObject());70const coff_section *CoffSec = COFFObjPtr->getCOFFSection(Sec);71bool isThumb = CoffSec->Characteristics & COFF::IMAGE_SCN_MEM_16BIT;7273Flags->getTargetFlags() = isThumb;7475return Flags;76}7778Align getStubAlignment() override { return Align(1); }7980Expected<object::relocation_iterator>81processRelocationRef(unsigned SectionID,82object::relocation_iterator RelI,83const object::ObjectFile &Obj,84ObjSectionToIDMap &ObjSectionToID,85StubMap &Stubs) override {86auto Symbol = RelI->getSymbol();87if (Symbol == Obj.symbol_end())88report_fatal_error("Unknown symbol in relocation");8990Expected<StringRef> TargetNameOrErr = Symbol->getName();91if (!TargetNameOrErr)92return TargetNameOrErr.takeError();93StringRef TargetName = *TargetNameOrErr;9495auto SectionOrErr = Symbol->getSection();96if (!SectionOrErr)97return SectionOrErr.takeError();98auto Section = *SectionOrErr;99100uint64_t RelType = RelI->getType();101uint64_t Offset = RelI->getOffset();102103// Determine the Addend used to adjust the relocation value.104uint64_t Addend = 0;105SectionEntry &AddendSection = Sections[SectionID];106uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;107uint8_t *Displacement = (uint8_t *)ObjTarget;108109switch (RelType) {110case COFF::IMAGE_REL_ARM_ADDR32:111case COFF::IMAGE_REL_ARM_ADDR32NB:112case COFF::IMAGE_REL_ARM_SECREL:113Addend = readBytesUnaligned(Displacement, 4);114break;115default:116break;117}118119#if !defined(NDEBUG)120SmallString<32> RelTypeName;121RelI->getTypeName(RelTypeName);122#endif123LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset124<< " RelType: " << RelTypeName << " TargetName: "125<< TargetName << " Addend " << Addend << "\n");126127bool IsExtern = Section == Obj.section_end();128unsigned TargetSectionID = -1;129uint64_t TargetOffset = -1;130131if (TargetName.starts_with(getImportSymbolPrefix())) {132TargetSectionID = SectionID;133TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);134TargetName = StringRef();135IsExtern = false;136} else if (!IsExtern) {137if (auto TargetSectionIDOrErr =138findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))139TargetSectionID = *TargetSectionIDOrErr;140else141return TargetSectionIDOrErr.takeError();142if (RelType != COFF::IMAGE_REL_ARM_SECTION)143TargetOffset = getSymbolOffset(*Symbol);144}145146if (IsExtern) {147RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);148addRelocationForSymbol(RE, TargetName);149} else {150151// We need to find out if the relocation is relative to a thumb function152// so that we include the ISA selection bit when resolve the relocation153bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section);154155switch (RelType) {156default: llvm_unreachable("unsupported relocation type");157case COFF::IMAGE_REL_ARM_ABSOLUTE:158// This relocation is ignored.159break;160case COFF::IMAGE_REL_ARM_ADDR32: {161RelocationEntry RE =162RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,163TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);164addRelocationForSection(RE, TargetSectionID);165break;166}167case COFF::IMAGE_REL_ARM_ADDR32NB: {168RelocationEntry RE =169RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,170TargetOffset, 0, 0, false, 0);171addRelocationForSection(RE, TargetSectionID);172break;173}174case COFF::IMAGE_REL_ARM_SECTION: {175RelocationEntry RE =176RelocationEntry(TargetSectionID, Offset, RelType, 0);177addRelocationForSection(RE, TargetSectionID);178break;179}180case COFF::IMAGE_REL_ARM_SECREL: {181RelocationEntry RE =182RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend);183addRelocationForSection(RE, TargetSectionID);184break;185}186case COFF::IMAGE_REL_ARM_MOV32T: {187RelocationEntry RE =188RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,189TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);190addRelocationForSection(RE, TargetSectionID);191break;192}193case COFF::IMAGE_REL_ARM_BRANCH20T:194case COFF::IMAGE_REL_ARM_BRANCH24T:195case COFF::IMAGE_REL_ARM_BLX23T: {196RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,197TargetOffset + Addend, true, 0);198addRelocationForSection(RE, TargetSectionID);199break;200}201}202}203204return ++RelI;205}206207void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {208const auto Section = Sections[RE.SectionID];209uint8_t *Target = Section.getAddressWithOffset(RE.Offset);210int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0;211212switch (RE.RelType) {213default: llvm_unreachable("unsupported relocation type");214case COFF::IMAGE_REL_ARM_ABSOLUTE:215// This relocation is ignored.216break;217case COFF::IMAGE_REL_ARM_ADDR32: {218// The target's 32-bit VA.219uint64_t Result =220RE.Sections.SectionA == static_cast<uint32_t>(-1)221? Value222: Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);223Result |= ISASelectionBit;224assert(Result <= UINT32_MAX && "relocation overflow");225LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset226<< " RelType: IMAGE_REL_ARM_ADDR32"227<< " TargetSection: " << RE.Sections.SectionA228<< " Value: " << format("0x%08" PRIx32, Result)229<< '\n');230writeBytesUnaligned(Result, Target, 4);231break;232}233case COFF::IMAGE_REL_ARM_ADDR32NB: {234// The target's 32-bit RVA.235// NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase236uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -237Sections[0].getLoadAddress() + RE.Addend;238assert(Result <= UINT32_MAX && "relocation overflow");239LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset240<< " RelType: IMAGE_REL_ARM_ADDR32NB"241<< " TargetSection: " << RE.Sections.SectionA242<< " Value: " << format("0x%08" PRIx32, Result)243<< '\n');244Result |= ISASelectionBit;245writeBytesUnaligned(Result, Target, 4);246break;247}248case COFF::IMAGE_REL_ARM_SECTION:249// 16-bit section index of the section that contains the target.250assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&251"relocation overflow");252LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset253<< " RelType: IMAGE_REL_ARM_SECTION Value: "254<< RE.SectionID << '\n');255writeBytesUnaligned(RE.SectionID, Target, 2);256break;257case COFF::IMAGE_REL_ARM_SECREL:258// 32-bit offset of the target from the beginning of its section.259assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&260"relocation overflow");261LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset262<< " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend263<< '\n');264writeBytesUnaligned(RE.Addend, Target, 2);265break;266case COFF::IMAGE_REL_ARM_MOV32T: {267// 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.268uint64_t Result =269Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);270assert(Result <= UINT32_MAX && "relocation overflow");271LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset272<< " RelType: IMAGE_REL_ARM_MOV32T"273<< " TargetSection: " << RE.Sections.SectionA274<< " Value: " << format("0x%08" PRIx32, Result)275<< '\n');276277// MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|278// imm32 = zext imm4:i:imm3:imm8279// MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|280// imm16 = imm4:i:imm3:imm8281282auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate) {283Bytes[0] |= ((Immediate & 0xf000) >> 12);284Bytes[1] |= ((Immediate & 0x0800) >> 11);285Bytes[2] |= ((Immediate & 0x00ff) >> 0);286Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4);287};288289EncodeImmediate(&Target[0],290(static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);291EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);292break;293}294case COFF::IMAGE_REL_ARM_BRANCH20T: {295// The most significant 20-bits of the signed 21-bit relative displacement296uint64_t Value =297RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;298assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&299"relocation overflow");300assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&301"relocation underflow");302LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset303<< " RelType: IMAGE_REL_ARM_BRANCH20T"304<< " Value: " << static_cast<int32_t>(Value) << '\n');305static_cast<void>(Value);306llvm_unreachable("unimplemented relocation");307break;308}309case COFF::IMAGE_REL_ARM_BRANCH24T: {310// The most significant 24-bits of the signed 25-bit relative displacement311uint64_t Value =312RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;313assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&314"relocation overflow");315assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&316"relocation underflow");317LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset318<< " RelType: IMAGE_REL_ARM_BRANCH24T"319<< " Value: " << static_cast<int32_t>(Value) << '\n');320static_cast<void>(Value);321llvm_unreachable("unimplemented relocation");322break;323}324case COFF::IMAGE_REL_ARM_BLX23T: {325// The most significant 24-bits of the signed 25-bit relative displacement326uint64_t Value =327RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;328assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&329"relocation overflow");330assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&331"relocation underflow");332LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset333<< " RelType: IMAGE_REL_ARM_BLX23T"334<< " Value: " << static_cast<int32_t>(Value) << '\n');335static_cast<void>(Value);336llvm_unreachable("unimplemented relocation");337break;338}339}340}341342void registerEHFrames() override {}343};344345}346347#endif348349350