diff --git a/lld/ELF/Arch/BPF.cpp b/lld/ELF/Arch/BPF.cpp new file mode 100644 --- /dev/null +++ b/lld/ELF/Arch/BPF.cpp @@ -0,0 +1,63 @@ +//===---- BPF.cpp ---------------------------------------------------------===// +// +// 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 "InputFiles.h" +#include "Symbols.h" +#include "Target.h" +#include "llvm/Object/ELF.h" + +using namespace llvm; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class BPF final : public TargetInfo { +public: + BPF(); + void relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; + RelType getDynRel(RelType type) const override; + RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const override; + bool emitFuncDataSections() const override; +}; +} // namespace + +BPF::BPF() { noneRel = R_BPF_NONE; } + +void BPF::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { + switch (rel.type) { + case R_BPF_NONE: + break; + case R_BPF_64_64: + write64(loc, val); + break; + case R_BPF_64_32: + write32(loc, val); + break; + default: + llvm_unreachable("unknown relocation"); + } +} + +RelType BPF::getDynRel(RelType type) const { return type; } + +RelExpr BPF::getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const { + if (type == R_BPF_NONE) + return R_NONE; + return R_ABS; +} + +bool BPF::emitFuncDataSections() const { return !config->relocatable; } + +TargetInfo *elf::getBPFTargetInfo() { + static BPF target; + return ⌖ +} diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -8,6 +8,7 @@ Arch/AMDGPU.cpp Arch/ARM.cpp Arch/AVR.cpp + Arch/BPF.cpp Arch/Hexagon.cpp Arch/Mips.cpp Arch/MipsArchTree.cpp diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -155,6 +155,7 @@ bool dependentLibraries; bool disableVerify; bool ehFrameHdr; + bool emitFuncDataSections; bool emitLLVM; bool emitRelocs; bool enableNewDtags; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2225,6 +2225,9 @@ symtab->scanVersionScript(); } + // Emit per func/datum sections if target permits. + config->emitFuncDataSections = target->emitFuncDataSections(); + // Do link-time optimization if given files are LLVM bitcode files. // This compiles bitcode files into real object files. // diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1626,6 +1626,9 @@ return EM_ARM; case Triple::avr: return EM_AVR; + case Triple::bpfel: + case Triple::bpfeb: + return EM_BPF; case Triple::mips: case Triple::mipsel: case Triple::mips64: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -491,8 +491,13 @@ if (RelTy::IsRela) p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr; - else if (config->relocatable && type != target->noneRel) - sec->relocations.push_back({R_ABS, type, rel.r_offset, addend, &sym}); + else if (config->relocatable) { + // For STT_SECTION symbols, BPF llvm target already wrote the + // section offset in each relocation instruction, so + // pushing to section relocations is not needed any more. + if (config->emachine != EM_BPF && type != target->noneRel) + sec->relocations.push_back({R_ABS, type, rel.r_offset, addend, &sym}); + } } else if (config->emachine == EM_PPC && type == R_PPC_PLTREL24 && p->r_addend >= 0x8000) { // Similar to R_MIPS_GPREL{16,32}. If the addend of R_PPC_PLTREL24 diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -84,9 +84,10 @@ c.Options.RelaxELFRelocations = true; c.Options.EmitAddrsig = true; - // Always emit a section per function/datum with LTO. - c.Options.FunctionSections = true; - c.Options.DataSections = true; + if (config->emitFuncDataSections) { + c.Options.FunctionSections = true; + c.Options.DataSections = true; + } // Check if basic block sections must be used. // Allowed values for --lto-basic-block-sections are "all", "labels", diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -35,6 +35,7 @@ virtual void writeIgotPlt(uint8_t *buf, const Symbol &s) const {} virtual int64_t getImplicitAddend(const uint8_t *buf, RelType type) const; virtual int getTlsGdRelaxSkip(RelType type) const { return 1; } + virtual bool emitFuncDataSections() const { return true; } // If lazy binding is supported, the first entry of the PLT has code // to call the dynamic linker to resolve PLT entries the first time @@ -174,6 +175,7 @@ TargetInfo *getAMDGPUTargetInfo(); TargetInfo *getARMTargetInfo(); TargetInfo *getAVRTargetInfo(); +TargetInfo *getBPFTargetInfo(); TargetInfo *getHexagonTargetInfo(); TargetInfo *getMSP430TargetInfo(); TargetInfo *getPPC64TargetInfo(); diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -60,6 +60,8 @@ return getARMTargetInfo(); case EM_AVR: return getAVRTargetInfo(); + case EM_BPF: + return getBPFTargetInfo(); case EM_HEXAGON: return getHexagonTargetInfo(); case EM_MIPS: diff --git a/lld/docs/index.rst b/lld/docs/index.rst --- a/lld/docs/index.rst +++ b/lld/docs/index.rst @@ -33,8 +33,8 @@ machine, you can expect that LLD runs more than twice as fast as the GNU gold linker. Your mileage may vary, though. -- It supports various CPUs/ABIs including AArch64, AMDGPU, ARM, Hexagon, MIPS - 32/64 big/little-endian, PowerPC, PowerPC64, RISC-V, SPARC V9, x86-32 and +- It supports various CPUs/ABIs including AArch64, AMDGPU, ARM, BPF, Hexagon, + MIPS 32/64 big/little-endian, PowerPC, PowerPC64, RISC-V, SPARC V9, x86-32 and x86-64. Among these, AArch64, ARM (>= v6), PowerPC, PowerPC64, x86-32 and x86-64 have production quality. MIPS seems decent too. diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -27,7 +27,7 @@ as GNU linkers. .Pp .Nm -currently supports i386, x86-64, ARM, AArch64, PowerPC32, PowerPC64, +currently supports i386, x86-64, ARM, AArch64, BPF, PowerPC32, PowerPC64, MIPS32, MIPS64, RISC-V, AMDGPU, Hexagon and SPARC V9 targets. .Nm acts as a Microsoft link.exe-compatible linker if invoked as diff --git a/lld/test/ELF/Inputs/bpf-lto-basic-1.ll b/lld/test/ELF/Inputs/bpf-lto-basic-1.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/Inputs/bpf-lto-basic-1.ll @@ -0,0 +1,104 @@ +; Source code: +; struct s { +; int a; +; int b; +; }; +; extern int foo(int); +; static __attribute__((noinline)) int add(int a, int b) { +; return a + b; +; } +; int bar(struct s *arg) { +; return add(arg->a, arg->b) + foo(arg->a); +; } +; Compilation flags: +; clang -target bpf -flto -O2 -g -S t1.c -o t1.ll + +; ModuleID = 't1.c' +source_filename = "t1.c" +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "bpf" + +%struct.s = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @bar(%struct.s* nocapture readonly %arg) local_unnamed_addr #0 !dbg !8 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !18, metadata !DIExpression()), !dbg !19 + %a = getelementptr inbounds %struct.s, %struct.s* %arg, i64 0, i32 0, !dbg !20 + %0 = load i32, i32* %a, align 4, !dbg !20, !tbaa !21 + %b = getelementptr inbounds %struct.s, %struct.s* %arg, i64 0, i32 1, !dbg !26 + %1 = load i32, i32* %b, align 4, !dbg !26, !tbaa !27 + %call = tail call fastcc i32 @add(i32 %0, i32 %1), !dbg !28 + %call2 = tail call i32 @foo(i32 %0) #4, !dbg !29 + %add = add nsw i32 %call2, %call, !dbg !30 + ret i32 %add, !dbg !31 +} + +; Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn mustprogress +define internal fastcc i32 @add(i32 %a, i32 %b) unnamed_addr #1 !dbg !32 { +entry: + call void @llvm.dbg.value(metadata i32 %a, metadata !36, metadata !DIExpression()), !dbg !38 + call void @llvm.dbg.value(metadata i32 %b, metadata !37, metadata !DIExpression()), !dbg !38 + %add = add nsw i32 %b, %a, !dbg !39 + ret i32 %add, !dbg !40 +} + +declare !dbg !41 dso_local i32 @foo(i32) local_unnamed_addr #2 + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree noinline norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #3 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 433a5046a139601b86ac0f5a8ce89c79e153ff06)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t1.c", directory: "/tmp/home/yhs/work/tests/llvm/lto") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"frame-pointer", i32 2} +!7 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 433a5046a139601b86ac0f5a8ce89c79e153ff06)"} +!8 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 9, type: !9, scopeLine: 9, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !17) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !12} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !14) +!14 = !{!15, !16} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !1, line: 2, baseType: !11, size: 32) +!16 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !13, file: !1, line: 3, baseType: !11, size: 32, offset: 32) +!17 = !{!18} +!18 = !DILocalVariable(name: "arg", arg: 1, scope: !8, file: !1, line: 9, type: !12) +!19 = !DILocation(line: 0, scope: !8) +!20 = !DILocation(line: 10, column: 19, scope: !8) +!21 = !{!22, !23, i64 0} +!22 = !{!"s", !23, i64 0, !23, i64 4} +!23 = !{!"int", !24, i64 0} +!24 = !{!"omnipotent char", !25, i64 0} +!25 = !{!"Simple C/C++ TBAA"} +!26 = !DILocation(line: 10, column: 27, scope: !8) +!27 = !{!22, !23, i64 4} +!28 = !DILocation(line: 10, column: 10, scope: !8) +!29 = !DILocation(line: 10, column: 32, scope: !8) +!30 = !DILocation(line: 10, column: 30, scope: !8) +!31 = !DILocation(line: 10, column: 3, scope: !8) +!32 = distinct !DISubprogram(name: "add", scope: !1, file: !1, line: 6, type: !33, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !35) +!33 = !DISubroutineType(types: !34) +!34 = !{!11, !11, !11} +!35 = !{!36, !37} +!36 = !DILocalVariable(name: "a", arg: 1, scope: !32, file: !1, line: 6, type: !11) +!37 = !DILocalVariable(name: "b", arg: 2, scope: !32, file: !1, line: 6, type: !11) +!38 = !DILocation(line: 0, scope: !32) +!39 = !DILocation(line: 7, column: 12, scope: !32) +!40 = !DILocation(line: 7, column: 3, scope: !32) +!41 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 5, type: !42, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!42 = !DISubroutineType(types: !43) +!43 = !{!11, !11} diff --git a/lld/test/ELF/Inputs/bpf-lto-basic-2.ll b/lld/test/ELF/Inputs/bpf-lto-basic-2.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/Inputs/bpf-lto-basic-2.ll @@ -0,0 +1,47 @@ +; Source code: +; int __attribute__((noinline)) foo(int a) { +; return a * a; +; } +; Compilation flags: +; clang -target bpf -flto -O2 -g -S t2.c -o t2.ll + +; ModuleID = 't2.c' +source_filename = "t2.c" +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "bpf" + +; Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn mustprogress +define dso_local i32 @foo(i32 %a) local_unnamed_addr #0 !dbg !8 { +entry: + call void @llvm.dbg.value(metadata i32 %a, metadata !13, metadata !DIExpression()), !dbg !14 + %mul = mul nsw i32 %a, %a, !dbg !15 + ret i32 %mul, !dbg !16 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nofree noinline norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 433a5046a139601b86ac0f5a8ce89c79e153ff06)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t2.c", directory: "/tmp/home/yhs/work/tests/llvm/lto") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"frame-pointer", i32 2} +!7 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 433a5046a139601b86ac0f5a8ce89c79e153ff06)"} +!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !{!13} +!13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 1, type: !11) +!14 = !DILocation(line: 0, scope: !8) +!15 = !DILocation(line: 2, column: 12, scope: !8) +!16 = !DILocation(line: 2, column: 3, scope: !8) diff --git a/lld/test/ELF/Inputs/bpf-lto-local-1.ll b/lld/test/ELF/Inputs/bpf-lto-local-1.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/Inputs/bpf-lto-local-1.ll @@ -0,0 +1,53 @@ +; Source code: +; static __attribute__((noinline)) __attribute__((section("sec1"))) +; int add(int a, int b) { +; return a + b; +; } +; static __attribute__((noinline)) __attribute__((section("sec1"))) +; int sub(int a, int b) { +; return a - b; +; } +; __attribute__((section("sec2"))) +; int bar(int a, int b) { +; return add(a, b) + sub(a, b); +; } +; Compilation flags: +; clang -target bpf -flto -O2 -S t1.c -o t1.ll + +; ModuleID = 't1.c' +source_filename = "t1.c" +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "bpf" + +; Function Attrs: nofree norecurse nosync nounwind readnone willreturn mustprogress +define dso_local i32 @bar(i32 %a, i32 %b) local_unnamed_addr #0 section "sec2" { +entry: + %call = tail call fastcc i32 @add(i32 %a, i32 %b) + %call1 = tail call fastcc i32 @sub(i32 %a, i32 %b) + %add = add nsw i32 %call1, %call + ret i32 %add +} + +; Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn mustprogress +define internal fastcc i32 @add(i32 %a, i32 %b) unnamed_addr #1 section "sec1" { +entry: + %add = add nsw i32 %b, %a + ret i32 %add +} + +; Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn mustprogress +define internal fastcc i32 @sub(i32 %a, i32 %b) unnamed_addr #1 section "sec1" { +entry: + %sub = sub nsw i32 %a, %b + ret i32 %sub +} + +attributes #0 = { nofree norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree noinline norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"frame-pointer", i32 2} +!2 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git c16909d7d1000413a32d3fcbc765dc082e8b62c0)"} diff --git a/lld/test/ELF/Inputs/bpf-lto-local-2.ll b/lld/test/ELF/Inputs/bpf-lto-local-2.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/Inputs/bpf-lto-local-2.ll @@ -0,0 +1,35 @@ +; Source code: +; static __attribute__((noinline)) __attribute__((section("sec3"))) +; int test() { +; return 0; +; } +; long test2() { return (long)&test; } +; Compilation flags: +; clang -target bpf -flto -O2 -S t2.c -o t2.ll + +; ModuleID = 't2.c' +source_filename = "t2.c" +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "bpf" + +; Function Attrs: nofree norecurse nosync nounwind readnone willreturn mustprogress +define dso_local i64 @test2() local_unnamed_addr #0 { +entry: + ret i64 ptrtoint (i32 ()* @test to i64) +} + +; Function Attrs: nofree noinline norecurse nosync nounwind readnone willreturn mustprogress +define internal i32 @test() #1 section "sec3" { +entry: + ret i32 0 +} + +attributes #0 = { nofree norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree noinline norecurse nosync nounwind readnone willreturn mustprogress "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"frame-pointer", i32 2} +!2 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git c16909d7d1000413a32d3fcbc765dc082e8b62c0)"} diff --git a/lld/test/ELF/bpf-basic.s b/lld/test/ELF/bpf-basic.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/bpf-basic.s @@ -0,0 +1,15 @@ +// REQUIRES: bpf +// RUN: echo 'define dso_local i32 @foo() local_unnamed_addr { entry: ret i32 0 }' > %t1.ll +// RUN: echo 'define dso_local i32 @bar() local_unnamed_addr { entry: ret i32 1 }' > %t2.ll +// RUN: llc -filetype=obj -mtriple=bpfel %t1.ll -o %t3 +// RUN: llc -filetype=obj -mtriple=bpfel %t2.ll -o %t4 +// RUN: ld.lld -relocatable %t3 %t4 -o %t5 +// RUN: llvm-objdump -d --no-show-raw-insn %t5 | FileCheck %s + +// CHECK: : +// CHECK: r0 = 0 +// CHECK: exit + +// CHECK: : +// CHECK: r0 = 1 +// CHECK: exit diff --git a/lld/test/ELF/bpf-lto-basic.s b/lld/test/ELF/bpf-lto-basic.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/bpf-lto-basic.s @@ -0,0 +1,18 @@ +// REQUIRES: bpf +// RUN: llvm-as %S/Inputs/bpf-lto-basic-1.ll -o %t1 +// RUN: llvm-as %S/Inputs/bpf-lto-basic-2.ll -o %t2 +// RUN: ld.lld -r %t1 %t2 -o %t3 +// RUN: llvm-objdump -d --no-show-raw-insn %t3 | FileCheck %s +// RUN: llvm-readelf -r %t3 | FileCheck -check-prefix=RELOC %s +// RUN: llvm-readelf -x ".BTF" %t3 | FileCheck -check-prefix=BTF %s + +// CHECK: : +// CHECK: call {{[0-9]+}} +// CHECK: call -1 +// CHECK: : +// CHECK: : + +// RELOC: R_BPF_64_32 {{[0-9a-f]+}} foo + +// BTF: 9feb0100 +// BTF-NOT: 9feb0100 diff --git a/lld/test/ELF/bpf-lto-local.s b/lld/test/ELF/bpf-lto-local.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/bpf-lto-local.s @@ -0,0 +1,18 @@ +// REQUIRES: bpf +// RUN: llvm-as %S/Inputs/bpf-lto-local-1.ll -o %t1 +// RUN: llvm-as %S/Inputs/bpf-lto-local-2.ll -o %t2 +// RUN: ld.lld -r %t1 %t2 -o %t3 +// RUN: llvm-objdump -d --no-show-raw-insn %t3 | FileCheck %s +// RUN: llvm-readelf -r %t3 | FileCheck -check-prefix=RELOC %s + +// CHECK: section .text: +// CHECK: r0 = 0 ll +// CHECK: section sec2: +// CHECK: call -1 +// CHECK: call 2 + +// RELOC: .rel.text +// RELOC: R_BPF_64_64 {{[0-9a-f]+}} sec3 +// RELOC: .relsec2 +// RELOC: R_BPF_64_32 {{[0-9a-f]+}} sec1 +// RELOC: R_BPF_64_32 {{[0-9a-f]+}} sec1 diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py --- a/lld/test/lit.cfg.py +++ b/lld/test/lit.cfg.py @@ -69,6 +69,7 @@ 'AMDGPU': 'amdgpu', 'ARM': 'arm', 'AVR': 'avr', + 'BPF': 'bpf', 'Hexagon': 'hexagon', 'Mips': 'mips', 'MSP430': 'msp430',