Skip to content

Commit

Permalink
[EraVM] Adding support of library linkage.
Browse files Browse the repository at this point in the history
  • Loading branch information
PavelKopyl committed Aug 31, 2024
1 parent 256a724 commit e702b66
Show file tree
Hide file tree
Showing 18 changed files with 296 additions and 21 deletions.
3 changes: 3 additions & 0 deletions lld/ELF/Arch/EraVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ void EraVM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
case R_ERAVM_16_SCALE_8:
add16scaled(val, /*scale=*/8);
break;
case R_ERAVM_32:
write32be(loc, static_cast<uint32_t>(val & 0xFFFFFFFF));
break;
default:
error(getErrorLocation(loc) + "unrecognized relocation " +
toString(rel.type));
Expand Down
4 changes: 3 additions & 1 deletion lld/include/lld-c/LLDAsLibraryC.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ LLVM_C_EXTERN_C_BEGIN
Input/output files are transferred via memory buffers. */
LLVMBool LLVMLinkEraVM(LLVMMemoryBufferRef inBuf, LLVMMemoryBufferRef *outBuf,
const char *metadataPtr, uint64_t metadataSize,
char **ErrorMessage);
const char *const *linkerSymbol,
const char linkerSymbolValue[][20],
uint64_t numLinkerSymbols, char **errorMessage);
LLVM_C_EXTERN_C_END

#endif // LLD_C_LLDASLIBRARYC_H
49 changes: 41 additions & 8 deletions lld/lld-c/LLDAsLibraryC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,33 @@

LLD_HAS_DRIVER_MEM_BUF(elf)

static std::string creteEraVMLinkerScript(const char *metadataPtr,
uint64_t metadataSize) {
constexpr static unsigned linkerSymbolSize = 20;

static std::string
creteEraVMLinkerScript(const char *metadataPtr, uint64_t metadataSize,
const char *const *linkerSymbol,
const char linkerSymbolValue[][linkerSymbolSize],
uint64_t numLinkerSymbols) {
constexpr unsigned relocSize = sizeof(uint32_t);
std::string linkerSymbols;
if (numLinkerSymbols) {
for (uint64_t SymNum = 0; SymNum < numLinkerSymbols; ++SymNum) {
llvm::StringRef symbolStr(linkerSymbol[SymNum]);
llvm::SmallString<linkerSymbolSize * 2> hexStrSymbolVal;
llvm::toHex(llvm::ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(
linkerSymbolValue[SymNum]),
linkerSymbolSize),
/*LowerCase*/ false, hexStrSymbolVal);
for (unsigned Idx = 0; Idx < linkerSymbolSize / relocSize; ++Idx) {
std::string IdxStr = std::to_string(Idx);
linkerSymbols +=
(symbolStr + llvm::Twine("_") + IdxStr + " = 0x" +
hexStrSymbolVal.substr(2 * relocSize * Idx, 2 * relocSize) + ";\n")
.str();
}
}
}

// The final bytecode should be padded such that its size be the
// odd number of words, i.e 2 * (N + 1).
std::string metadata;
Expand Down Expand Up @@ -46,7 +71,9 @@ static std::string creteEraVMLinkerScript(const char *metadataPtr,
}

llvm::Twine scriptPart1 = llvm::Twine("\
SECTIONS { \n\
SECTIONS {\n");

llvm::Twine scriptPart2 = llvm::Twine("\
.code : SUBALIGN(8) { \n\
*(.text) \n\
\n\
Expand All @@ -63,7 +90,7 @@ SECTIONS { \n\
\n\
/* Add padding with metadata */\n");

llvm::Twine scriptPart2 = llvm::Twine("\
llvm::Twine scriptPart3 = llvm::Twine("\
ASSERT(. % 64 == 32, \"size isn't odd number of words\"); \n\
\n\
/* Check the total binary size is not more than (2^16 - 2) words. */ \n\
Expand All @@ -76,16 +103,22 @@ SECTIONS { \n\
*(.data) \n\
}}");

return (scriptPart1 + padding + "\n" + metadata + "\n" + scriptPart2).str();
return (scriptPart1 + linkerSymbols + scriptPart2 + padding + "\n" +
metadata + "\n" + scriptPart3)
.str();
}

LLVMBool LLVMLinkEraVM(LLVMMemoryBufferRef inBuffer,
LLVMMemoryBufferRef *outBuffer, const char *metadataPtr,
uint64_t metadataSize, char **ErrorMessage) {
uint64_t metadataSize, const char *const *linkerSymbol,
const char linkerSymbolValue[][linkerSymbolSize],
uint64_t numLinkerSymbols, char **errorMessage) {
llvm::SmallVector<llvm::MemoryBufferRef> localInMemBufRefs(2);
localInMemBufRefs[0] = *llvm::unwrap(inBuffer);

std::string linkerScript = creteEraVMLinkerScript(metadataPtr, metadataSize);
std::string linkerScript =
creteEraVMLinkerScript(metadataPtr, metadataSize, linkerSymbol,
linkerSymbolValue, numLinkerSymbols);

std::unique_ptr<llvm::MemoryBuffer> linkerScriptBuf =
llvm::MemoryBuffer::getMemBuffer(linkerScript, "1");
Expand Down Expand Up @@ -117,7 +150,7 @@ LLVMBool LLVMLinkEraVM(LLVMMemoryBufferRef inBuffer,
// For unification with other LLVM C-API functions, return 'true' in case of
// an error.
if (!Ret) {
*ErrorMessage = strdup(errorString.c_str());
*errorMessage = strdup(errorString.c_str());
return true;
}

Expand Down
6 changes: 6 additions & 0 deletions lld/test/ELF/Inputs/eravm.lds
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ SECTIONS {
*(.data)
} > stack
}

library_sybol_0 = 0x01010101;
library_sybol_1 = 0x02020202;
library_sybol_2 = 0x03030303;
library_sybol_3 = 0x04040404;
library_sybol_4 = 0x05050505;
29 changes: 23 additions & 6 deletions lld/test/ELF/eravm-data-reloc.s
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
; REQUIRES: eravm
; RUN: llvm-mc -filetype=obj -arch=eravm %s -o %t.o
; RUN: llvm-objdump --no-leading-addr --disassemble --reloc %t.o | FileCheck --check-prefix=INPUT %s
; RUN: llvm-objdump --no-leading-addr --reloc %t.o | FileCheck --check-prefix=INPUT-LIBSYM %s
; RUN: ld.lld -T %S/Inputs/eravm.lds %t.o -o %t
; RUN: llvm-objdump --no-leading-addr --disassemble --reloc --syms %t | FileCheck --check-prefix=OUTPUT %s

Expand Down Expand Up @@ -61,16 +62,21 @@ array_const_local:
; OUTPUT-NEXT: 00000000 l O .code 00000000 dummy_const
; OUTPUT-NEXT: 00000020 l O .code 00000000 scalar_const_local
; OUTPUT-NEXT: 00000040 l O .code 00000000 array_const_local
; OUTPUT-NEXT: 000000a0 l .code 00000000 reloc_src_g
; OUTPUT-NEXT: 000000c8 l .code 00000000 reloc_src_l
; OUTPUT-NEXT: 000000f0 l .code 00000000 reloc_dst_g
; OUTPUT-NEXT: 00000108 l .code 00000000 reloc_dst_l
; OUTPUT-NEXT: 00000120 l .code 00000000 reloc_both_g
; OUTPUT-NEXT: 00000148 l .code 00000000 reloc_both_l
; OUTPUT-NEXT: 000000c0 l .code 00000000 reloc_src_g
; OUTPUT-NEXT: 000000e8 l .code 00000000 reloc_src_l
; OUTPUT-NEXT: 00000110 l .code 00000000 reloc_dst_g
; OUTPUT-NEXT: 00000128 l .code 00000000 reloc_dst_l
; OUTPUT-NEXT: 00000140 l .code 00000000 reloc_both_g
; OUTPUT-NEXT: 00000168 l .code 00000000 reloc_both_l
; OUTPUT-NEXT: 00001020 g O .stack 00000000 scalar_var
; OUTPUT-NEXT: 00001040 g O .stack 00000000 array_var
; OUTPUT-NEXT: 00000020 g O .code 00000000 scalar_const
; OUTPUT-NEXT: 00000040 g O .code 00000000 array_const
; OUTPUT-NEXT: 01010101 g *ABS* 00000000 library_sybol_0
; OUTPUT-NEXT: 02020202 g *ABS* 00000000 library_sybol_1
; OUTPUT-NEXT: 03030303 g *ABS* 00000000 library_sybol_2
; OUTPUT-NEXT: 04040404 g *ABS* 00000000 library_sybol_3
; OUTPUT-NEXT: 05050505 g *ABS* 00000000 library_sybol_4

.text
.p2align 3
Expand Down Expand Up @@ -209,3 +215,14 @@ reloc_both_l:
; OUTPUT-NEXT: 00 81 00 03 00 10 00 47 add code[3], r1, stack[129 + r0]
; OUTPUT-NEXT: 00 81 00 83 00 10 00 37 add stack[131 + r0], r1, stack[129 + r0]
; OUTPUT-NEXT: 00 00 00 00 00 01 04 2d ret

.rodata
.linker_symbol:
.library_address_cell @library_sybol
; INPUT-LIBSYM: RELOCATION RECORDS FOR [.rodata]:
; INPUT-LIBSYM-NEXT: OFFSET TYPE VALUE
; INPUT-LIBSYM-NEXT: 000000ac R_ERAVM_32 library_sybol_0
; INPUT-LIBSYM-NEXT: 000000b0 R_ERAVM_32 library_sybol_1
; INPUT-LIBSYM-NEXT: 000000b4 R_ERAVM_32 library_sybol_2
; INPUT-LIBSYM-NEXT: 000000b8 R_ERAVM_32 library_sybol_3
; INPUT-LIBSYM-NEXT: 000000bc R_ERAVM_32 library_sybol_4
67 changes: 65 additions & 2 deletions lld/unittests/EraVM/LLDTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,73 @@ define i256 @get_glob() nounwind { \n\

LLVMMemoryBufferRef BinMemBuffer;
if (LLVMLinkEraVM(ObjMemBuffer, &BinMemBuffer,
/*metadataPtr*/ nullptr, 0, &ErrMsg)) {
/*metadataPtr*/ nullptr, 0, nullptr, nullptr, 0, &ErrMsg)) {
FAIL() << "Failed to link:" << ErrMsg;
LLVMDisposeMessage(ErrMsg);
return;
}
EXPECT_TRUE(LLVMGetBufferSize(BinMemBuffer) % 64 == 32);
LLVMDisposeMemoryBuffer(ObjMemBuffer);
LLVMDisposeMemoryBuffer(BinMemBuffer);
}

TEST_F(LLDCTest, LinkerSymbol) {
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 @test() { \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_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);

LLVMMemoryBufferRef BinMemBuffer;
const char *LinkerSymbol[2] = {"library_id", "library_id2"};
const char LinkerSymbolVal[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}};
if (LLVMLinkEraVM(ObjMemBuffer, &BinMemBuffer,
/*metadataPtr*/ nullptr, 0, LinkerSymbol, LinkerSymbolVal,
2, &ErrMsg)) {
FAIL() << "Failed to link:" << ErrMsg;
LLVMDisposeMessage(ErrMsg);
return;
}
StringRef Val1(LinkerSymbolVal[0], 20);
StringRef Val2(LinkerSymbolVal[1], 20);
StringRef Binary(LLVMGetBufferStart(BinMemBuffer),
LLVMGetBufferSize(BinMemBuffer));
EXPECT_TRUE(Binary.find(Val1) != StringRef::npos);
EXPECT_TRUE(Binary.find(Val2) != StringRef::npos);
EXPECT_TRUE(LLVMGetBufferSize(BinMemBuffer) % 64 == 32);
LLVMDisposeMemoryBuffer(ObjMemBuffer);
LLVMDisposeMemoryBuffer(BinMemBuffer);
}
Expand Down Expand Up @@ -134,7 +196,8 @@ define void @glob() nounwind { \n\
LLVMMemoryBufferRef BinMemBuffer;
// Return code 'true' denotes an error.
EXPECT_TRUE(LLVMLinkEraVM(ObjMemBuffer, &BinMemBuffer,
/*metadataPtr*/ nullptr, 0, &ErrMsg));
/*metadataPtr*/ nullptr, 0, nullptr, nullptr, 0,
&ErrMsg));
EXPECT_TRUE(StringRef(ErrMsg).contains("undefined symbol: foo"));

LLVMDisposeMessage(ErrMsg);
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/BinaryFormat/ELFRelocs/EraVM.def
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
ELF_RELOC(R_ERAVM_NONE, 0)
ELF_RELOC(R_ERAVM_16_SCALE_32, 1)
ELF_RELOC(R_ERAVM_16_SCALE_8, 2)
ELF_RELOC(R_ERAVM_32, 3)
9 changes: 9 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsEraVM.td
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,13 @@ def int_eravm_ptr_pack : Intrinsic<[LLVMQualPointerType<3>], [LLVMQualPointerTyp
def int_eravm_ptr_shrink : Intrinsic<[LLVMQualPointerType<3>], [LLVMQualPointerType<3>, llvm_i256_ty], [IntrNoMem, IntrWillReturn]>;
def int_eravm_ptr_add : Intrinsic<[LLVMQualPointerType<3>], [LLVMQualPointerType<3>, llvm_i256_ty], [IntrNoMem, IntrWillReturn]>;
def int_eravm_ptrtoint : Intrinsic<[llvm_i256_ty], [LLVMQualPointerType<3>], [IntrNoMem, IntrWillReturn]>;

// Linking of libraries.

// Inserts a library address placeholder, which will be replced with
// the finall library address by the linker.
def int_eravm_linkersymbol : DefaultAttrsIntrinsic<
[llvm_i256_ty], [llvm_metadata_ty],
[IntrNoMem, IntrWillReturn]
>;
}
22 changes: 22 additions & 0 deletions llvm/lib/Target/EraVM/AsmParser/EraVMAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,28 @@ bool EraVMAsmParser::ParseDirective(AsmToken DirectiveID) {

return false;
}
// Parses directive:
// ::= .library_address_cell @(@identificator | "string")
if (DirectiveID.getString() == ".library_address_cell") {
if (!getLexer().is(AsmToken::At))
return TokError("expected symbol name starting with @");
Lex(); // eat "@" token

StringRef SymbolName;
// if (getTok().is(AsmToken::Identifier))
// SymbolName = getTok().getString().str();
if (getParser().parseIdentifier(SymbolName))
return TokError("expected symbol name");

if (parseEOL())
return true;

MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolName);
auto *TS = getStreamer().getTargetStreamer();
static_cast<EraVMTargetStreamer *>(TS)->emitLibraryAddressSymbol(Symbol);

return false;
}
return true;
}

Expand Down
35 changes: 35 additions & 0 deletions llvm/lib/Target/EraVM/EraVMAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class EraVMAsmPrinter : public AsmPrinter {
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
const MachineInstr *MI);

void emitLibraryAddressSymbol(const MachineInstr *MI);

void emitInstruction(const MachineInstr *MI) override;
using AliasMapTy = DenseMap<uint64_t, SmallVector<const GlobalAlias *, 1>>;
void emitGlobalConstant(const DataLayout &DL, const Constant *CV,
Expand Down Expand Up @@ -128,6 +130,10 @@ void EraVMAsmPrinter::emitInstruction(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, TmpInst);
return;
}
if (Opc == EraVM::LinkerSymbol) {
emitLibraryAddressSymbol(MI);
return;
}

if (MI->isPseudo()) {
#ifndef NDEBUG
Expand All @@ -140,6 +146,35 @@ void EraVMAsmPrinter::emitInstruction(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, TmpInst);
}

void EraVMAsmPrinter::emitLibraryAddressSymbol(const MachineInstr *MI) {
MCInst MCI;
MCI.setOpcode(EraVM::ADDcrr_s);
// Code reference.
MCSymbol *Label = OutContext.createNamedTempSymbol("linker_symbol");
const MCExpr *LabelExpr = MCSymbolRefExpr::create(Label, OutContext);
auto *TS =
static_cast<EraVMTargetStreamer *>(OutStreamer->getTargetStreamer());

// Dest register
MCI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
MCI.addOperand(MCOperand::createReg(EraVM::R0));
MCI.addOperand(MCOperand::createExpr(LabelExpr));
MCI.addOperand(MCOperand::createReg(EraVM::R0));
// Operand: cc
MCI.addOperand(MCOperand::createImm(0));
EmitToStreamer(*OutStreamer, MCI);

// Now emit the .rodata entry.
MCSection *CurrentSection = OutStreamer->getCurrentSectionOnly();
MCSection *ReadOnlySection =
OutContext.getELFSection(".rodata", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
OutStreamer->switchSection(ReadOnlySection);
OutStreamer->emitLabel(Label);
MCSymbol *LibraryAddressSymbol = MI->getOperand(1).getMCSymbol();
TS->emitLibraryAddressSymbol(LibraryAddressSymbol);
OutStreamer->switchSection(CurrentSection);
}

void EraVMAsmPrinter::emitJumpTableInfo() {
// The default implementation would try to emit 256-bit fixup, so provide
// custom implementation based on emitJumpTableInfo and emitJumpTableEntry
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/EraVM/EraVMISD.def
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ HANDLE_NODETYPE(LOG_DECOMMIT)
HANDLE_NODETYPE(GAStack)
HANDLE_NODETYPE(GACode)
HANDLE_NODETYPE(TRAP)
HANDLE_NODETYPE(LINKER_SYMBOL)

// Flag setting operations.
HANDLE_NODETYPE(ADD_V)
HANDLE_NODETYPE(SUB_V)
HANDLE_NODETYPE(MUL_V)
HANDLE_NODETYPE(MUL_V)
Loading

0 comments on commit e702b66

Please sign in to comment.