178 lines
7 KiB
C++
178 lines
7 KiB
C++
//===------ StubsTests.cpp - Unit tests for generic stub generation -------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
|
|
#include "llvm/ExecutionEngine/JITLink/aarch64.h"
|
|
#include "llvm/ExecutionEngine/JITLink/i386.h"
|
|
#include "llvm/ExecutionEngine/JITLink/loongarch.h"
|
|
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
|
|
#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
|
|
#include "llvm/Support/Memory.h"
|
|
|
|
#include "llvm/Testing/Support/Error.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::jitlink;
|
|
|
|
static std::pair<Symbol &, Symbol &>
|
|
GenerateStub(LinkGraph &G, size_t PointerSize, Edge::Kind PointerEdgeKind) {
|
|
auto &FuncSymbol = G.addAbsoluteSymbol("Func", orc::ExecutorAddr(0x2000), 0,
|
|
Linkage::Strong, Scope::Default, true);
|
|
|
|
// Create a section for pointer symbols.
|
|
auto &PointersSec =
|
|
G.createSection("__pointers", orc::MemProt::Read | orc::MemProt::Write);
|
|
|
|
// Create a section for jump stubs symbols.
|
|
auto &StubsSec =
|
|
G.createSection("__stubs", orc::MemProt::Read | orc::MemProt::Write);
|
|
|
|
auto AnonymousPtrCreator = getAnonymousPointerCreator(G.getTargetTriple());
|
|
EXPECT_TRUE(AnonymousPtrCreator);
|
|
|
|
auto PointerSym = AnonymousPtrCreator(G, PointersSec, &FuncSymbol, 0);
|
|
EXPECT_FALSE(errorToBool(PointerSym.takeError()));
|
|
EXPECT_EQ(std::distance(PointerSym->getBlock().edges().begin(),
|
|
PointerSym->getBlock().edges().end()),
|
|
1U);
|
|
auto &DeltaEdge = *PointerSym->getBlock().edges().begin();
|
|
EXPECT_EQ(DeltaEdge.getKind(), PointerEdgeKind);
|
|
EXPECT_EQ(&DeltaEdge.getTarget(), &FuncSymbol);
|
|
EXPECT_EQ(PointerSym->getBlock().getSize(), PointerSize);
|
|
EXPECT_TRUE(all_of(PointerSym->getBlock().getContent(),
|
|
[](char x) { return x == 0; }));
|
|
|
|
auto PtrJumpStubCreator = getPointerJumpStubCreator(G.getTargetTriple());
|
|
EXPECT_TRUE(PtrJumpStubCreator);
|
|
auto StubSym = PtrJumpStubCreator(G, StubsSec, *PointerSym);
|
|
EXPECT_FALSE(errorToBool(StubSym.takeError()));
|
|
return {*PointerSym, *StubSym};
|
|
}
|
|
|
|
TEST(StubsTest, StubsGeneration_x86_64) {
|
|
const char PointerJumpStubContent[6] = {
|
|
static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00};
|
|
LinkGraph G("foo", Triple("x86_64-apple-darwin"), 8, llvm::endianness::little,
|
|
getGenericEdgeKindName);
|
|
auto [PointerSym, StubSym] = GenerateStub(G, 8U, x86_64::Pointer64);
|
|
|
|
EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(),
|
|
StubSym.getBlock().edges().end()),
|
|
1U);
|
|
auto &JumpEdge = *StubSym.getBlock().edges().begin();
|
|
EXPECT_EQ(JumpEdge.getKind(), x86_64::BranchPCRel32);
|
|
EXPECT_EQ(&JumpEdge.getTarget(), &PointerSym);
|
|
EXPECT_EQ(StubSym.getBlock().getContent(),
|
|
ArrayRef<char>(PointerJumpStubContent));
|
|
}
|
|
|
|
TEST(StubsTest, StubsGeneration_aarch64) {
|
|
const char PointerJumpStubContent[12] = {
|
|
0x10, 0x00, 0x00, (char)0x90u, // ADRP x16, <imm>@page21
|
|
0x10, 0x02, 0x40, (char)0xf9u, // LDR x16, [x16, <imm>@pageoff12]
|
|
0x00, 0x02, 0x1f, (char)0xd6u // BR x16
|
|
};
|
|
LinkGraph G("foo", Triple("aarch64-linux-gnu"), 8, llvm::endianness::little,
|
|
getGenericEdgeKindName);
|
|
auto [PointerSym, StubSym] = GenerateStub(G, 8U, aarch64::Pointer64);
|
|
|
|
EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(),
|
|
StubSym.getBlock().edges().end()),
|
|
2U);
|
|
auto &AdrpHighEdge = *StubSym.getBlock().edges().begin();
|
|
auto &LdrEdge = *++StubSym.getBlock().edges().begin();
|
|
EXPECT_EQ(AdrpHighEdge.getKind(), aarch64::Page21);
|
|
EXPECT_EQ(&AdrpHighEdge.getTarget(), &PointerSym);
|
|
EXPECT_EQ(LdrEdge.getKind(), aarch64::PageOffset12);
|
|
EXPECT_EQ(&LdrEdge.getTarget(), &PointerSym);
|
|
EXPECT_EQ(StubSym.getBlock().getContent(),
|
|
ArrayRef<char>(PointerJumpStubContent));
|
|
}
|
|
|
|
TEST(StubsTest, StubsGeneration_i386) {
|
|
const char PointerJumpStubContent[6] = {
|
|
static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00};
|
|
LinkGraph G("foo", Triple("i386-unknown-linux-gnu"), 4,
|
|
llvm::endianness::little, getGenericEdgeKindName);
|
|
auto [PointerSym, StubSym] = GenerateStub(G, 4U, i386::Pointer32);
|
|
|
|
EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(),
|
|
StubSym.getBlock().edges().end()),
|
|
1U);
|
|
auto &JumpEdge = *StubSym.getBlock().edges().begin();
|
|
EXPECT_EQ(JumpEdge.getKind(), i386::Pointer32);
|
|
EXPECT_EQ(&JumpEdge.getTarget(), &PointerSym);
|
|
EXPECT_EQ(StubSym.getBlock().getContent(),
|
|
ArrayRef<char>(PointerJumpStubContent));
|
|
}
|
|
|
|
TEST(StubsTest, StubsGeneration_loongarch32) {
|
|
const char PointerJumpStubContent[12] = {
|
|
0x14,
|
|
0x00,
|
|
0x00,
|
|
0x1a, // pcalau12i $t8, %page20(imm)
|
|
static_cast<char>(0x94),
|
|
0x02,
|
|
static_cast<char>(0x80),
|
|
0x28, // ld.d $t8, $t8, %pageoff12(imm)
|
|
static_cast<char>(0x80),
|
|
0x02,
|
|
0x00,
|
|
0x4c // jr $t8
|
|
};
|
|
LinkGraph G("foo", Triple("loongarch32"), 4, llvm::endianness::little,
|
|
getGenericEdgeKindName);
|
|
auto [PointerSym, StubSym] = GenerateStub(G, 4U, loongarch::Pointer32);
|
|
|
|
EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(),
|
|
StubSym.getBlock().edges().end()),
|
|
2U);
|
|
auto &PageHighEdge = *StubSym.getBlock().edges().begin();
|
|
auto &PageLowEdge = *++StubSym.getBlock().edges().begin();
|
|
EXPECT_EQ(PageHighEdge.getKind(), loongarch::Page20);
|
|
EXPECT_EQ(&PageHighEdge.getTarget(), &PointerSym);
|
|
EXPECT_EQ(PageLowEdge.getKind(), loongarch::PageOffset12);
|
|
EXPECT_EQ(&PageLowEdge.getTarget(), &PointerSym);
|
|
EXPECT_EQ(StubSym.getBlock().getContent(),
|
|
ArrayRef<char>(PointerJumpStubContent));
|
|
}
|
|
|
|
TEST(StubsTest, StubsGeneration_loongarch64) {
|
|
const char PointerJumpStubContent[12] = {
|
|
0x14,
|
|
0x00,
|
|
0x00,
|
|
0x1a, // pcalau12i $t8, %page20(imm)
|
|
static_cast<char>(0x94),
|
|
0x02,
|
|
static_cast<char>(0xc0),
|
|
0x28, // ld.d $t8, $t8, %pageoff12(imm)
|
|
static_cast<char>(0x80),
|
|
0x02,
|
|
0x00,
|
|
0x4c // jr $t8
|
|
};
|
|
LinkGraph G("foo", Triple("loongarch64"), 8, llvm::endianness::little,
|
|
getGenericEdgeKindName);
|
|
auto [PointerSym, StubSym] = GenerateStub(G, 8U, loongarch::Pointer64);
|
|
|
|
EXPECT_EQ(std::distance(StubSym.getBlock().edges().begin(),
|
|
StubSym.getBlock().edges().end()),
|
|
2U);
|
|
auto &PageHighEdge = *StubSym.getBlock().edges().begin();
|
|
auto &PageLowEdge = *++StubSym.getBlock().edges().begin();
|
|
EXPECT_EQ(PageHighEdge.getKind(), loongarch::Page20);
|
|
EXPECT_EQ(&PageHighEdge.getTarget(), &PointerSym);
|
|
EXPECT_EQ(PageLowEdge.getKind(), loongarch::PageOffset12);
|
|
EXPECT_EQ(&PageLowEdge.getTarget(), &PointerSym);
|
|
EXPECT_EQ(StubSym.getBlock().getContent(),
|
|
ArrayRef<char>(PointerJumpStubContent));
|
|
}
|