diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 15ca2ddbbae046..baf70cbccc8c5c 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -277,6 +277,12 @@ void IRExecutionUnit::GetRunnableInfo(Status &error, lldb::addr_t &func_addr, .setMCJITMemoryManager(std::make_unique(*this)) .setOptLevel(llvm::CodeGenOptLevel::Less); + // Resulted jitted code can be placed too far from the code in the binary + // and thus can contain more than +-2GB jumps, that are not available + // in RISC-V without large code model. + if (triple.isRISCV64()) + builder.setCodeModel(llvm::CodeModel::Large); + llvm::StringRef mArch; llvm::StringRef mCPU; llvm::SmallVector mAttrs; diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp index de304183f67175..38d452b6ab560c 100644 --- a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp +++ b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp @@ -10,7 +10,9 @@ #include #include +#include +#include "llvm/ADT/STLExtras.h" #include "llvm/IR/DerivedTypes.h" #include "Utility/RISCV_DWARF_Registers.h" @@ -20,6 +22,7 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/RegisterValue.h" #define DEFINE_REG_NAME(reg_num) ConstString(#reg_num).GetCString() @@ -120,6 +123,10 @@ static const std::array g_register_infos = { } // namespace dwarf } // namespace +// Number of argument registers (the base integer calling convention +// provides 8 argument registers, a0-a7) +static constexpr size_t g_regs_for_args_count = 8U; + const RegisterInfo *ABISysV_riscv::GetRegisterInfoArray(uint32_t &count) { count = dwarf::g_register_infos.size(); return dwarf::g_register_infos.data(); @@ -164,11 +171,81 @@ TotalArgsSizeInWords(bool is_rv64, return total_size; } +static bool UpdateRegister(RegisterContext *reg_ctx, + const lldb::RegisterKind reg_kind, + const uint32_t reg_num, const addr_t value) { + Log *log = GetLog(LLDBLog::Expressions); + + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(reg_kind, reg_num); + + LLDB_LOG(log, "Writing {0}: 0x{1:x}", reg_info->name, + static_cast(value)); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, value)) { + LLDB_LOG(log, "Writing {0}: failed", reg_info->name); + return false; + } + return true; +} + +static void LogInitInfo(Log &log, const Thread &thread, addr_t sp, + addr_t func_addr, addr_t return_addr, + const llvm::ArrayRef args) { + std::stringstream ss; + ss << "ABISysV_riscv::PrepareTrivialCall" + << " (tid = 0x" << std::hex << thread.GetID() << ", sp = 0x" << sp + << ", func_addr = 0x" << func_addr << ", return_addr = 0x" << return_addr; + + for (auto [idx, arg] : enumerate(args)) + ss << ", arg" << std::dec << idx << " = 0x" << std::hex << arg; + ss << ")"; + log.PutString(ss.str()); +} + bool ABISysV_riscv::PrepareTrivialCall(Thread &thread, addr_t sp, addr_t func_addr, addr_t return_addr, llvm::ArrayRef args) const { - // TODO: Implement - return false; + Log *log = GetLog(LLDBLog::Expressions); + if (log) + LogInitInfo(*log, thread, sp, func_addr, return_addr, args); + + const auto reg_ctx_sp = thread.GetRegisterContext(); + if (!reg_ctx_sp) { + LLDB_LOG(log, "Failed to get RegisterContext"); + return false; + } + + if (args.size() > g_regs_for_args_count) { + LLDB_LOG(log, "Function has {0} arguments, but only {1} are allowed!", + args.size(), g_regs_for_args_count); + return false; + } + + // Write arguments to registers + for (auto [idx, arg] : enumerate(args)) { + const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + idx); + LLDB_LOG(log, "About to write arg{0} (0x{1:x}) into {2}", idx, arg, + reg_info->name); + + if (!reg_ctx_sp->WriteRegisterFromUnsigned(reg_info, arg)) { + LLDB_LOG(log, "Failed to write arg{0} (0x{1:x}) into {2}", idx, arg, + reg_info->name); + return false; + } + } + + if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC, func_addr)) + return false; + if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_SP, sp)) + return false; + if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_RA, return_addr)) + return false; + + LLDB_LOG(log, "ABISysV_riscv::{0}() success", __FUNCTION__); + return true; } bool ABISysV_riscv::PrepareTrivialCall( @@ -222,14 +299,14 @@ bool ABISysV_riscv::PrepareTrivialCall( assert(prototype.getFunctionNumParams() == args.size()); const size_t num_args = args.size(); - const size_t regs_for_args_count = 8U; const size_t num_args_in_regs = - num_args > regs_for_args_count ? regs_for_args_count : num_args; + num_args > g_regs_for_args_count ? g_regs_for_args_count : num_args; // Number of arguments passed on stack. size_t args_size = TotalArgsSizeInWords(m_is_rv64, args); - auto on_stack = - args_size <= regs_for_args_count ? 0 : args_size - regs_for_args_count; + auto on_stack = args_size <= g_regs_for_args_count + ? 0 + : args_size - g_regs_for_args_count; auto offset = on_stack * word_size; uint8_t reg_value[8]; @@ -260,7 +337,7 @@ bool ABISysV_riscv::PrepareTrivialCall( ++reg_index; } - if (reg_index < regs_for_args_count || size == 0) + if (reg_index < g_regs_for_args_count || size == 0) continue; // Remaining arguments are passed on the stack. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 9b056ea73a77fb..39f0e6269cd0f0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -44,6 +44,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/TargetParser/Triple.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -442,24 +443,50 @@ static void SetupDefaultClangDiagnostics(CompilerInstance &compiler) { /// \return /// A string representing target ABI for the current architecture. static std::string GetClangTargetABI(const ArchSpec &target_arch) { - std::string abi; - if (target_arch.IsMIPS()) { switch (target_arch.GetFlags() & ArchSpec::eMIPSABI_mask) { case ArchSpec::eMIPSABI_N64: - abi = "n64"; - break; + return "n64"; case ArchSpec::eMIPSABI_N32: - abi = "n32"; - break; + return "n32"; case ArchSpec::eMIPSABI_O32: - abi = "o32"; - break; + return "o32"; default: - break; + return {}; } } - return abi; + + if (target_arch.GetTriple().isRISCV64()) { + switch (target_arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask) { + case ArchSpec::eRISCV_float_abi_soft: + return "lp64"; + case ArchSpec::eRISCV_float_abi_single: + return "lp64f"; + case ArchSpec::eRISCV_float_abi_double: + return "lp64d"; + case ArchSpec::eRISCV_float_abi_quad: + return "lp64q"; + default: + return {}; + } + } + + if (target_arch.GetTriple().isRISCV32()) { + switch (target_arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask) { + case ArchSpec::eRISCV_float_abi_soft: + return "ilp32"; + case ArchSpec::eRISCV_float_abi_single: + return "ilp32f"; + case ArchSpec::eRISCV_float_abi_double: + return "ilp32d"; + case ArchSpec::eRISCV_float_abi_soft | ArchSpec::eRISCV_rve: + return "ilp32e"; + default: + return {}; + } + } + + return {}; } static void SetupTargetOpts(CompilerInstance &compiler, @@ -506,6 +533,18 @@ static void SetupTargetOpts(CompilerInstance &compiler, // Set the target ABI if (std::string abi = GetClangTargetABI(target_arch); !abi.empty()) compiler.getTargetOpts().ABI = std::move(abi); + + if ((target_machine == llvm::Triple::riscv64 && + compiler.getTargetOpts().ABI == "lp64f") || + (target_machine == llvm::Triple::riscv32 && + compiler.getTargetOpts().ABI == "ilp32f")) + compiler.getTargetOpts().FeaturesAsWritten.emplace_back("+f"); + + if ((target_machine == llvm::Triple::riscv64 && + compiler.getTargetOpts().ABI == "lp64d") || + (target_machine == llvm::Triple::riscv32 && + compiler.getTargetOpts().ABI == "ilp32d")) + compiler.getTargetOpts().FeaturesAsWritten.emplace_back("+d"); } static void SetupLangOpts(CompilerInstance &compiler, @@ -757,7 +796,7 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->getCodeGenOpts().EmitDeclMetadata = true; m_compiler->getCodeGenOpts().InstrumentFunctions = false; m_compiler->getCodeGenOpts().setFramePointer( - CodeGenOptions::FramePointerKind::All); + CodeGenOptions::FramePointerKind::All); if (generate_debug_info) m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo); else @@ -771,7 +810,7 @@ ClangExpressionParser::ClangExpressionParser( // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. m_compiler->getTarget().adjust(m_compiler->getDiagnostics(), - m_compiler->getLangOpts()); + m_compiler->getLangOpts()); // 5. Set up the diagnostic buffer for reporting errors auto diag_mgr = new ClangDiagnosticManagerAdapter( @@ -1191,8 +1230,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, if (auto fileEntry = m_compiler->getFileManager().getOptionalFileRef( result_path)) { source_mgr.setMainFileID(source_mgr.createFileID( - *fileEntry, - SourceLocation(), SrcMgr::C_User)); + *fileEntry, SourceLocation(), SrcMgr::C_User)); created_main_file = true; } } diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index b4e088d5339466..92f37c22ae5132 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -1011,6 +1011,135 @@ void RuntimeDyldELF::resolveBPFRelocation(const SectionEntry &Section, } } +static void applyUTypeImmRISCV(uint8_t *InstrAddr, uint32_t Imm) { + uint32_t UpperImm = (Imm + 0x800) & 0xfffff000; + auto Instr = support::ulittle32_t::ref(InstrAddr); + Instr = (Instr & 0xfff) | UpperImm; +} + +static void applyITypeImmRISCV(uint8_t *InstrAddr, uint32_t Imm) { + uint32_t LowerImm = Imm & 0xfff; + auto Instr = support::ulittle32_t::ref(InstrAddr); + Instr = (Instr & 0xfffff) | (LowerImm << 20); +} + +void RuntimeDyldELF::resolveRISCVRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, + SID SectionID) { + switch (Type) { + default: { + std::string Err = "Unimplemented reloc type: " + std::to_string(Type); + llvm::report_fatal_error(Err.c_str()); + } + // 32-bit PC-relative function call, macros call, tail (PIC) + // Write first 20 bits of 32 bit value to the auipc instruction + // Last 12 bits to the jalr instruction + case ELF::R_RISCV_CALL: + case ELF::R_RISCV_CALL_PLT: { + uint64_t P = Section.getLoadAddressWithOffset(Offset); + uint64_t PCOffset = Value + Addend - P; + applyUTypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + applyITypeImmRISCV(Section.getAddressWithOffset(Offset + 4), PCOffset); + break; + } + // High 20 bits of 32-bit absolute address, %hi(symbol) + case ELF::R_RISCV_HI20: { + uint64_t PCOffset = Value + Addend; + applyUTypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + break; + } + // Low 12 bits of 32-bit absolute address, %lo(symbol) + case ELF::R_RISCV_LO12_I: { + uint64_t PCOffset = Value + Addend; + applyITypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + break; + } + // High 20 bits of 32-bit PC-relative reference, %pcrel_hi(symbol) + case ELF::R_RISCV_GOT_HI20: + case ELF::R_RISCV_PCREL_HI20: { + uint64_t P = Section.getLoadAddressWithOffset(Offset); + uint64_t PCOffset = Value + Addend - P; + applyUTypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + break; + } + + // label: + // auipc a0, %pcrel_hi(symbol) // R_RISCV_PCREL_HI20 + // addi a0, a0, %pcrel_lo(label) // R_RISCV_PCREL_LO12_I + // + // The low 12 bits of relative address between pc and symbol. + // The symbol is related to the high part instruction which is marked by + // label. + case ELF::R_RISCV_PCREL_LO12_I: { + for (auto &&PendingReloc : PendingRelocs) { + const RelocationValueRef &MatchingValue = PendingReloc.first; + RelocationEntry &Reloc = PendingReloc.second; + uint64_t HIRelocPC = + getSectionLoadAddress(Reloc.SectionID) + Reloc.Offset; + if (Value + Addend == HIRelocPC) { + uint64_t Symbol = getSectionLoadAddress(MatchingValue.SectionID) + + MatchingValue.Addend; + auto PCOffset = Symbol - HIRelocPC; + applyITypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + return; + } + } + + llvm::report_fatal_error( + "R_RISCV_PCREL_LO12_I without matching R_RISCV_PCREL_HI20"); + } + case ELF::R_RISCV_32_PCREL: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + int64_t RealOffset = Value + Addend - FinalAddress; + int32_t TruncOffset = Lo_32(RealOffset); + support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = + TruncOffset; + break; + } + case ELF::R_RISCV_32: { + auto Ref = support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Value + Addend; + break; + } + case ELF::R_RISCV_64: { + auto Ref = support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Value + Addend; + break; + } + case ELF::R_RISCV_ADD16: { + auto Ref = support::ulittle16_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref + Value + Addend; + break; + } + case ELF::R_RISCV_ADD32: { + auto Ref = support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref + Value + Addend; + break; + } + case ELF::R_RISCV_ADD64: { + auto Ref = support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref + Value + Addend; + break; + } + case ELF::R_RISCV_SUB16: { + auto Ref = support::ulittle16_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref - Value - Addend; + break; + } + case ELF::R_RISCV_SUB32: { + auto Ref = support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref - Value - Addend; + break; + } + case ELF::R_RISCV_SUB64: { + auto Ref = support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref - Value - Addend; + break; + } + } +} + // The target location for the relocation is described by RE.SectionID and // RE.Offset. RE.SectionID can be used to find the SectionEntry. Each // SectionEntry has three members describing its location. @@ -1076,12 +1205,17 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, case Triple::bpfeb: resolveBPFRelocation(Section, Offset, Value, Type, Addend); break; + case Triple::riscv32: // Fall through. + case Triple::riscv64: + resolveRISCVRelocation(Section, Offset, Value, Type, Addend, SectionID); + break; default: llvm_unreachable("Unsupported CPU type!"); } } -void *RuntimeDyldELF::computePlaceholderAddress(unsigned SectionID, uint64_t Offset) const { +void *RuntimeDyldELF::computePlaceholderAddress(unsigned SectionID, + uint64_t Offset) const { return (void *)(Sections[SectionID].getObjAddress() + Offset); } @@ -1870,7 +2004,8 @@ RuntimeDyldELF::processRelocationRef( Value.Addend += support::ulittle32_t::ref(computePlaceholderAddress(SectionID, Offset)); processSimpleRelocation(SectionID, Offset, RelType, Value); } else if (RelType == ELF::R_X86_64_PC64) { - Value.Addend += support::ulittle64_t::ref(computePlaceholderAddress(SectionID, Offset)); + Value.Addend += support::ulittle64_t::ref( + computePlaceholderAddress(SectionID, Offset)); processSimpleRelocation(SectionID, Offset, RelType, Value); } else if (RelType == ELF::R_X86_64_GOTTPOFF) { processX86_64GOTTPOFFRelocation(SectionID, Offset, Value, Addend); @@ -1884,9 +2019,23 @@ RuntimeDyldELF::processRelocationRef( } else { processSimpleRelocation(SectionID, Offset, RelType, Value); } + } else if (Arch == Triple::riscv32 || Arch == Triple::riscv64) { + // *_LO12 relocation receive information about a symbol from the + // corresponding *_HI20 relocation, so we have to collect this information + // before resolving + if (RelType == ELF::R_RISCV_GOT_HI20 || + RelType == ELF::R_RISCV_PCREL_HI20 || + RelType == ELF::R_RISCV_TPREL_HI20 || + RelType == ELF::R_RISCV_TLS_GD_HI20 || + RelType == ELF::R_RISCV_TLS_GOT_HI20) { + RelocationEntry RE(SectionID, Offset, RelType, Addend); + PendingRelocs.push_back({Value, RE}); + } + processSimpleRelocation(SectionID, Offset, RelType, Value); } else { if (Arch == Triple::x86) { - Value.Addend += support::ulittle32_t::ref(computePlaceholderAddress(SectionID, Offset)); + Value.Addend += support::ulittle32_t::ref( + computePlaceholderAddress(SectionID, Offset)); } processSimpleRelocation(SectionID, Offset, RelType, Value); } diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index 1b90013dfe2df9..97517884654bc5 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -58,6 +58,10 @@ class RuntimeDyldELF : public RuntimeDyldImpl { void resolveBPFRelocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend); + void resolveRISCVRelocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, + SID SectionID); + unsigned getMaxStubSize() const override { if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be) return 20; // movz; movk; movk; movk; br @@ -146,6 +150,9 @@ class RuntimeDyldELF : public RuntimeDyldImpl { // *HI16 relocations will be added for resolving when we find matching // *LO16 part. (Mips specific) + // + // *HI20 relocations will be added for resolving when we find matching + // *LO12 part. (RISC-V specific) SmallVector, 8> PendingRelocs; // When a module is loaded we save the SectionID of the EH frame section