diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -255,7 +255,25 @@ std::unique_ptr MCE) : MCELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)) {} + void emitFill(const MCExpr &NumBytes, uint64_t FillValue, + SMLoc Loc) override { + emitDataMappingSymbol(); + MCObjectStreamer::emitFill(NumBytes, FillValue, Loc); + } + + void changeSection(MCSection *Section, const MCExpr *Subsection) override { + LastMappingSymbols[getCurrentSection().first] = std::move(LastEMSInfo); + MCELFStreamer::changeSection(Section, Subsection); + auto LastMappingSymbol = LastMappingSymbols.find(Section); + if (LastMappingSymbol != LastMappingSymbols.end()) { + LastEMSInfo = std::move(LastMappingSymbol->second); + return; + } + LastEMSInfo.reset(new ElfMappingSymbolInfo(SMLoc(), nullptr, EMS_None)); + } + void emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override { + emitDataMappingSymbol(); const MCExpr *A, *B; if (!requiresFixups(getContext(), Value, A, B)) return MCELFStreamer::emitValueImpl(Value, Size, Loc); @@ -276,6 +294,99 @@ DF->getContents().resize(DF->getContents().size() + Size, 0); } + + /// This function is the one used to emit instruction data into the ELF + /// streamer. We override it to add the appropriate mapping symbol if + /// necessary. + void emitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) override { + EmitISAMappingSymbol(); + MCELFStreamer::emitInstruction(Inst, STI); + } + + /// This is one of the functions used to emit data into an ELF section, so the + /// RISCV streamer overrides it to add the appropriate mapping symbol ($d) if + /// necessary. + void emitBytes(StringRef Data) override { + emitDataMappingSymbol(); + MCELFStreamer::emitBytes(Data); + } + +private: + enum ElfMappingSymbol { EMS_None, EMS_ISA, EMS_Data }; + + struct ElfMappingSymbolInfo { + explicit ElfMappingSymbolInfo(SMLoc Loc, MCFragment *F, uint64_t O) + : Loc(Loc), F(F), Offset(O), State(EMS_None) {} + void resetInfo() { + F = nullptr; + Offset = 0; + } + bool hasInfo() { return F != nullptr; } + SMLoc Loc; + MCFragment *F; + uint64_t Offset; + ElfMappingSymbol State; + }; + + void emitDataMappingSymbol() { + if (LastEMSInfo->State == EMS_Data) + return; + else if (LastEMSInfo->State == EMS_None) { + ElfMappingSymbolInfo *EMS = LastEMSInfo.get(); + auto *DF = dyn_cast_or_null(getCurrentFragment()); + if (!DF) + return; + EMS->Loc = SMLoc(); + EMS->F = getCurrentFragment(); + EMS->Offset = DF->getContents().size(); + LastEMSInfo->State = EMS_Data; + return; + } + EmitMappingSymbol("$d"); + LastEMSInfo->State = EMS_Data; + } + + void FlushPendingMappingSymbol() { + if (!LastEMSInfo->hasInfo()) + return; + ElfMappingSymbolInfo *EMS = LastEMSInfo.get(); + EmitMappingSymbol("$d", EMS->Loc, EMS->F, EMS->Offset); + EMS->resetInfo(); + } + + void EmitISAMappingSymbol() { + if (LastEMSInfo->State == EMS_ISA) + return; + FlushPendingMappingSymbol(); + EmitMappingSymbol("$x"); + LastEMSInfo->State = EMS_ISA; + } + + void EmitMappingSymbol(StringRef Name, SMLoc Loc, MCFragment *F, + uint64_t Offset) { + auto *Symbol = cast(getContext().getOrCreateSymbol( + Name + "." + Twine(MappingSymbolCounter++))); + emitLabelAtPos(Symbol, Loc, F, Offset); + Symbol->setType(ELF::STT_NOTYPE); + Symbol->setBinding(ELF::STB_LOCAL); + } + + void EmitMappingSymbol(StringRef Name) { + auto *Symbol = cast(getContext().getOrCreateSymbol( + Name + "." + Twine(MappingSymbolCounter++))); + emitLabel(Symbol); + + Symbol->setType(ELF::STT_NOTYPE); + Symbol->setBinding(ELF::STB_LOCAL); + } + + int64_t MappingSymbolCounter = 0; + + DenseMap> + LastMappingSymbols; + + std::unique_ptr LastEMSInfo; }; } // namespace diff --git a/llvm/test/MC/RISCV/Inputs/1.s b/llvm/test/MC/RISCV/Inputs/1.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/Inputs/1.s @@ -0,0 +1,3 @@ + .section .foobar,"ax",%progbits + nop + .word 32 diff --git a/llvm/test/MC/RISCV/Inputs/2.s b/llvm/test/MC/RISCV/Inputs/2.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/Inputs/2.s @@ -0,0 +1,3 @@ + .section .foobar,"",%progbits + nop + .word 32 diff --git a/llvm/test/MC/RISCV/Inputs/3.s b/llvm/test/MC/RISCV/Inputs/3.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/Inputs/3.s @@ -0,0 +1,3 @@ + .section .foobar,"aw",%progbits + nop + .word 32 diff --git a/llvm/test/MC/RISCV/Inputs/4.s b/llvm/test/MC/RISCV/Inputs/4.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/Inputs/4.s @@ -0,0 +1,2 @@ + .section .foobar,"",%progbits + .word 32 diff --git a/llvm/test/MC/RISCV/Inputs/5.s b/llvm/test/MC/RISCV/Inputs/5.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/Inputs/5.s @@ -0,0 +1,2 @@ + .section .foobar,"aw",%progbits + .word 32 diff --git a/llvm/test/MC/RISCV/Inputs/6.s b/llvm/test/MC/RISCV/Inputs/6.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/Inputs/6.s @@ -0,0 +1,12 @@ + .section .foo + .word 30 + .word 31 + .word 32 + .word 33 + nop + .word 34 + .word 35 + .word 36 + .word 37 + .word 38 + nop diff --git a/llvm/test/MC/RISCV/Inputs/7.s b/llvm/test/MC/RISCV/Inputs/7.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/Inputs/7.s @@ -0,0 +1,3 @@ + .section .foobar,"aw",%progbits + .word 32 + nop diff --git a/llvm/test/MC/RISCV/Inputs/ident.s b/llvm/test/MC/RISCV/Inputs/ident.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/Inputs/ident.s @@ -0,0 +1 @@ + .ident "LLVM RISCV Compiler" diff --git a/llvm/test/MC/RISCV/mapping-symbols.s b/llvm/test/MC/RISCV/mapping-symbols.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/mapping-symbols.s @@ -0,0 +1,44 @@ +# Check section containing code and data with permission executable for the section. +@ RUN: llvm-mc -triple=riscv64 -filetype=obj -o %t.o %p/Inputs/1.s +@ RUN: llvm-readelf -s %t.o | FileCheck %s + +# Check section containing code and data with no permissions for the section. +@ RUN: llvm-mc -triple=riscv64 -filetype=obj -o %t.o %p/Inputs/2.s +@ RUN: llvm-readelf -s %t.o | FileCheck %s + +# Check section containing code and data with read/write permissions for the section. +@ RUN: llvm-mc -triple=riscv64 -filetype=obj -o %t.o %p/Inputs/3.s +@ RUN: llvm-readelf -s %t.o | FileCheck %s + +# Check section containing data with no permissions for the section. +@ RUN: llvm-mc -triple=riscv64 -filetype=obj -o %t.o %p/Inputs/4.s +@ RUN: llvm-readelf -s %t.o | FileCheck %s -check-prefix=MAPPINGSYMBOLS + +# Check section containing only data with read/write permissions for the section. +@ RUN: llvm-mc -triple=riscv64 -filetype=obj -o %t.o %p/Inputs/5.s +@ RUN: llvm-readelf -s %t.o | FileCheck %s -check-prefix=MAPPINGSYMBOLS + +# Check section containing the ident string with no permissions for the section. +@ RUN: llvm-mc -triple=riscv64 -filetype=obj -o %t.o %p/Inputs/ident.s +@ RUN: llvm-readelf -s %t.o | FileCheck %s -check-prefix=MAPPINGSYMBOLS + +# Check section containing code and data with no permissions for the section. +# data comes before code. +@ RUN: llvm-mc -triple=riscv64 -filetype=obj -o %t.o %p/Inputs/6.s +@ RUN: llvm-readelf -s %t.o | FileCheck %s -check-prefix=MIX + +# Check section containing code and data with no permissions for the section. +# data comes before code. +@ RUN: llvm-mc -triple=riscv64 -filetype=obj -o %t.o %p/Inputs/7.s +@ RUN: llvm-readelf -s %t.o | FileCheck %s + +#CHECK-DAG: $x +#CHECK-DAG: $d + +#MIX: $d +#MIX: $x +#MIX: $d +#MIX: $x + +#MAPPINGSYMBOLS-NOT: $x +#MAPPINGSYMBOLS-NOT: $d diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -458,8 +458,14 @@ return Elf && Elf->getEMachine() == ELF::EM_CSKY; } +static bool isRISCVElf(const ObjectFile &Obj) { + const auto *Elf = dyn_cast(&Obj); + return Elf && Elf->getEMachine() == ELF::EM_RISCV; +} + static bool hasMappingSymbols(const ObjectFile &Obj) { - return isArmElf(Obj) || isAArch64Elf(Obj) || isCSKYElf(Obj) ; + return isArmElf(Obj) || isAArch64Elf(Obj) || isCSKYElf(Obj) || + isRISCVElf(Obj); } static void printRelocation(formatted_raw_ostream &OS, StringRef FileName,