Skip to content

Commit

Permalink
[EraVM] Fix: handle duplicating library symbols
Browse files Browse the repository at this point in the history
There may be an arbitrary number of 'Linkersymbol' instructions
with the same argument. Map them to the unique MCSymbol.
  • Loading branch information
PavelKopyl authored and hedgar2017 committed Oct 31, 2024
1 parent 2a03cc8 commit a58b8f5
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 13 deletions.
120 changes: 120 additions & 0 deletions lld/unittests/EraVM/LLDTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,126 @@ define i256 @test() { \n\
LLVMDisposeMemoryBuffer(BinMemBuffer);
}

TEST_F(LLDCTest, IterativeLinkageRepeatedLibraries) {
StringRef LLVMIr = "\
target datalayout = \"E-p:256:256-i256:256:256-S32-a:256:256\" \n\
target triple = \"eravm\" \n\
declare i256 @llvm.eravm.linkersymbol(metadata) \n\
\n\
define i256 @foo() { \n\
%res = call i256 @llvm.eravm.linkersymbol(metadata !1) \n\
%res2 = call i256 @llvm.eravm.linkersymbol(metadata !3) \n\
%res3 = add i256 %res, %res2 \n\
ret i256 %res3 \n\
} \n\
\n\
define i256 @bar() { \n\
%res = call i256 @llvm.eravm.linkersymbol(metadata !1) \n\
%res2 = call i256 @llvm.eravm.linkersymbol(metadata !2) \n\
%res3 = add i256 %res, %res2 \n\
ret i256 %res3 \n\
} \n\
\n\
!1 = !{!\"library_id\"} \n\
!2 = !{!\"library_id\"} \n\
!3 = !{!\"library_id2\"}";

// Wrap Source in a MemoryBuffer
LLVMMemoryBufferRef IrMemBuffer = LLVMCreateMemoryBufferWithMemoryRange(
LLVMIr.data(), LLVMIr.size(), "test", 1);
char *ErrMsg = nullptr;
LLVMModuleRef M;
if (LLVMParseIRInContext(Context, IrMemBuffer, &M, &ErrMsg)) {
FAIL() << "Failed to parse llvm ir:" << ErrMsg;
LLVMDisposeMessage(ErrMsg);
return;
}

// Run CodeGen to produce the buffer.
LLVMMemoryBufferRef ObjMemBuffer;
if (LLVMTargetMachineEmitToMemoryBuffer(TM, M, LLVMObjectFile, &ErrMsg,
&ObjMemBuffer)) {
FAIL() << "Failed to compile llvm ir:" << ErrMsg;
LLVMDisposeModule(M);
LLVMDisposeMessage(ErrMsg);
return;
}
LLVMDisposeModule(M);

EXPECT_TRUE(LLVMIsELFEraVM(ObjMemBuffer));

uint64_t NumUndefLinkerSymbols = 0;
const char *LinkerSymbols[2] = {"library_id", "library_id2"};
const char LinkerSymbolVals[2][20] = {
{1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5},
{6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 11, 12, 13}};

char **UndefLinkerSymbols =
LLVMGetUndefinedLinkerSymbolsEraVM(ObjMemBuffer, &NumUndefLinkerSymbols);
EXPECT_TRUE(NumUndefLinkerSymbols == 2);
EXPECT_TRUE((std::strcmp(UndefLinkerSymbols[0], LinkerSymbols[0]) == 0) ||
(std::strcmp(UndefLinkerSymbols[0], LinkerSymbols[1]) == 0));
EXPECT_TRUE((std::strcmp(UndefLinkerSymbols[1], LinkerSymbols[0]) == 0) ||
(std::strcmp(UndefLinkerSymbols[1], LinkerSymbols[1]) == 0));

LLVMDisposeUndefinedLinkerSymbolsEraVM(UndefLinkerSymbols,
NumUndefLinkerSymbols);

// Pass only the first linker symbol.
LLVMMemoryBufferRef Obj2MemBuffer;
if (LLVMLinkEraVM(ObjMemBuffer, &Obj2MemBuffer, LinkerSymbols,
LinkerSymbolVals, 1, &ErrMsg)) {
FAIL() << "Failed to link:" << ErrMsg;
LLVMDisposeMessage(ErrMsg);
return;
}

EXPECT_TRUE(LLVMIsELFEraVM(Obj2MemBuffer));
UndefLinkerSymbols =
LLVMGetUndefinedLinkerSymbolsEraVM(Obj2MemBuffer, &NumUndefLinkerSymbols);
EXPECT_TRUE(NumUndefLinkerSymbols == 1);
EXPECT_TRUE(std::strcmp(UndefLinkerSymbols[0], LinkerSymbols[1]) == 0);

LLVMDisposeUndefinedLinkerSymbolsEraVM(UndefLinkerSymbols,
NumUndefLinkerSymbols);

// Pass only the second linker symbol. This time
// the linker should emit the final bytecode, as all the
// symbols are resolved.
LLVMMemoryBufferRef BinMemBuffer;
if (LLVMLinkEraVM(Obj2MemBuffer, &BinMemBuffer, &LinkerSymbols[1],
&LinkerSymbolVals[1], 1, &ErrMsg)) {
FAIL() << "Failed to link:" << ErrMsg;
LLVMDisposeMessage(ErrMsg);
return;
}

{
LLVMMemoryBufferRef Bin2MemBuffer;
EXPECT_TRUE(LLVMLinkEraVM(BinMemBuffer, &Bin2MemBuffer, nullptr, nullptr, 0,
&ErrMsg));
EXPECT_TRUE(
StringRef(ErrMsg).contains("Input binary is not an EraVM ELF file"));
LLVMDisposeMessage(ErrMsg);
}

EXPECT_FALSE(LLVMIsELFEraVM(BinMemBuffer));
UndefLinkerSymbols =
LLVMGetUndefinedLinkerSymbolsEraVM(BinMemBuffer, &NumUndefLinkerSymbols);
EXPECT_TRUE(NumUndefLinkerSymbols == 0);

StringRef Val1(LinkerSymbolVals[0], 20);
StringRef Val2(LinkerSymbolVals[1], 20);
StringRef Binary(LLVMGetBufferStart(BinMemBuffer),
LLVMGetBufferSize(BinMemBuffer));
EXPECT_TRUE(Binary.count(Val1) == 1);
EXPECT_TRUE(Binary.count(Val2) == 1);
EXPECT_TRUE(LLVMGetBufferSize(BinMemBuffer) % 64 == 32);
LLVMDisposeMemoryBuffer(ObjMemBuffer);
LLVMDisposeMemoryBuffer(Obj2MemBuffer);
LLVMDisposeMemoryBuffer(BinMemBuffer);
}

TEST_F(LLDCTest, LinkError) {
StringRef LLVMIr = "\
target datalayout = \"E-p:256:256-i256:256:256-S32-a:256:256\" \n\
Expand Down
5 changes: 0 additions & 5 deletions llvm/lib/MC/MCC/AssemblerC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,6 @@ LLVMBool LLVMDisassembleEraVM(LLVMTargetMachineRef T,
break;
}

#ifndef NDEBUG
if (ConstantSectionStart != std::numeric_limits<uint64_t>::max())
assert(PC == ConstantSectionStart * WordSize);
#endif

while (PC + WordSize <= BytesNum) {
uint64_t Word = PC / WordSize;
assert(PC % WordSize == 0);
Expand Down
29 changes: 21 additions & 8 deletions llvm/lib/Target/EraVM/EraVMAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "MCTargetDesc/EraVMInstPrinter.h"
#include "MCTargetDesc/EraVMTargetStreamer.h"
#include "TargetInfo/EraVMTargetInfo.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
Expand Down Expand Up @@ -60,6 +61,8 @@ class EraVMAsmPrinter : public AsmPrinter {
std::map<const Constant *, std::vector<MCSymbol *>>;
std::vector<const Constant *> UniqueConstants;
ConstantPoolMapType ConstantPoolMap;
// Maps linker symbol name to corresponding MCSymbol.
StringMap<MCSymbol *> LinkerSymbolMap;

public:
EraVMAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
Expand Down Expand Up @@ -146,7 +149,7 @@ void EraVMAsmPrinter::emitInstruction(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, TmpInst);
}

// The LinkerSymbol instruction is lowered in the following:
// The LinkerSymbol instruction is lowered to the following:
//
// .rodata
// .linker_symbol0:
Expand All @@ -158,8 +161,13 @@ void EraVMAsmPrinter::emitInstruction(const MachineInstr *MI) {
void EraVMAsmPrinter::emitLibraryAddressSymbol(const MachineInstr *MI) {
MCInst MCI;
MCI.setOpcode(EraVM::ADDcrr_s);

// Code reference.
MCSymbol *Label = OutContext.createNamedTempSymbol("linker_symbol");
MCSymbol *LinkerSymbol = MI->getOperand(1).getMCSymbol();
StringRef LinkerSymbolName = LinkerSymbol->getName();
MCSymbol *Label = LinkerSymbolMap.contains(LinkerSymbolName)
? LinkerSymbolMap[LinkerSymbolName]
: OutContext.createNamedTempSymbol("linker_symbol");
const MCExpr *LabelExpr = MCSymbolRefExpr::create(Label, OutContext);
auto *TS =
static_cast<EraVMTargetStreamer *>(OutStreamer->getTargetStreamer());
Expand All @@ -173,9 +181,13 @@ void EraVMAsmPrinter::emitLibraryAddressSymbol(const MachineInstr *MI) {
MCI.addOperand(MCOperand::createImm(0));
EmitToStreamer(*OutStreamer, MCI);

MCSymbol *LinkerSymbol = MI->getOperand(1).getMCSymbol();
StringRef SymbolName = LinkerSymbol->getName();
std::string SymbolNameHash = EraVM::getLinkerSymbolHash(SymbolName);
// The linker symbol and the related section already exist, so just exit.
if (LinkerSymbolMap.contains(LinkerSymbolName))
return;

LinkerSymbolMap[LinkerSymbolName] = Label;

std::string SymbolNameHash = EraVM::getLinkerSymbolHash(LinkerSymbolName);
MCSymbol *LinkerSymbolHash = OutContext.getOrCreateSymbol(SymbolNameHash);

// Emit the .rodata entry.
Expand All @@ -188,13 +200,13 @@ void EraVMAsmPrinter::emitLibraryAddressSymbol(const MachineInstr *MI) {

// Emit the .linker_symbol_name section that contains the actual symbol
// name.
std::string LinkerSymbolSectionName =
EraVM::getLinkerSymbolSectionName(EraVM::getLinkerSymbolHash(SymbolName));
std::string LinkerSymbolSectionName = EraVM::getLinkerSymbolSectionName(
EraVM::getLinkerSymbolHash(LinkerSymbolName));

MCSection *LinkerSymbolSection = OutContext.getELFSection(
LinkerSymbolSectionName, ELF::SHT_PROGBITS, ELF::SHF_STRINGS);
OutStreamer->switchSection(LinkerSymbolSection);
OutStreamer->emitBytes(SymbolName);
OutStreamer->emitBytes(LinkerSymbolName);

OutStreamer->switchSection(CurrentSection);
}
Expand Down Expand Up @@ -270,6 +282,7 @@ void EraVMAsmPrinter::emitEndOfAsmFile(Module &) {
// after emitting all the things, we also need to clear symbol cache
UniqueConstants.clear();
ConstantPoolMap.clear();
LinkerSymbolMap.clear();
}

void EraVMAsmPrinter::insertSymbolToConstantMap(const Constant *C,
Expand Down
22 changes: 22 additions & 0 deletions llvm/test/CodeGen/EraVM/no-linker-symbols-duplication.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
; RUN: llc < %s | FileCheck %s

target datalayout = "E-p:256:256-i256:256:256-S32-a:256:256"
target triple = "eravm"

declare i256 @llvm.eravm.linkersymbol(metadata)

; CHECK: .linker_symbol0:
; CHECK-NOT: .linker_symbol1:

define i256 @foo() {
%res = call i256 @llvm.eravm.linkersymbol(metadata !1)
ret i256 %res
}

define i256 @bar() {
%res = call i256 @llvm.eravm.linkersymbol(metadata !2)
ret i256 %res
}

!1 = !{!"library_id"}
!2 = !{!"library_id"}

0 comments on commit a58b8f5

Please sign in to comment.