diff --git a/lld/test/ELF/riscv-variant-cc.s b/lld/test/ELF/riscv-variant-cc.s --- a/lld/test/ELF/riscv-variant-cc.s +++ b/lld/test/ELF/riscv-variant-cc.s @@ -45,7 +45,7 @@ # CHECK5: 0 NOTYPE GLOBAL DEFAULT [VARIANT_CC] UND func_global_undef # CHECK5-NEXT: 0 NOTYPE GLOBAL DEFAULT [VARIANT_CC] [[#]] func_global_def # CHECK5-NEXT: 0 IFUNC GLOBAL DEFAULT [VARIANT_CC] [[#]] ifunc_global_def -# CHECK5: Symbol table '.symtab' contains 9 entries: +# CHECK5: Symbol table '.symtab' contains 10 entries: # CHECK5: 0 NOTYPE LOCAL DEFAULT [VARIANT_CC] [[#]] func_local # CHECK5-NEXT: 0 IFUNC LOCAL DEFAULT [VARIANT_CC] [[#]] ifunc_local # CHECK5: 0 NOTYPE LOCAL HIDDEN [VARIANT_CC] [[#]] func_global_hidden diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -16,12 +16,27 @@ class RISCVELFStreamer : public MCELFStreamer { void reset() override; + void emitDataMappingSymbol(); + void emitInstructionsMappingSymbol(); + void emitMappingSymbol(StringRef Name); + + enum ElfMappingSymbol { EMS_None, EMS_Instructions, EMS_Data }; + + int64_t MappingSymbolCounter; + DenseMap LastMappingSymbols; + ElfMappingSymbol LastEMS; public: RISCVELFStreamer(MCContext &C, std::unique_ptr MAB, std::unique_ptr MOW, std::unique_ptr MCE) : MCELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)) {} + + void changeSection(MCSection *Section, const MCExpr *Subsection) override; + void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; + void emitBytes(StringRef Data) override; + void emitFill(const MCExpr &NumBytes, uint64_t FillValue, SMLoc Loc) override; + void emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override; }; namespace llvm { 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 @@ -125,6 +125,65 @@ void RISCVELFStreamer::reset() { static_cast(getTargetStreamer())->reset(); MCELFStreamer::reset(); + MappingSymbolCounter = 0; + LastMappingSymbols.clear(); + LastEMS = EMS_None; +} + +void RISCVELFStreamer::emitDataMappingSymbol() { + if (LastEMS == EMS_Data) + return; + emitMappingSymbol("$d"); + LastEMS = EMS_Data; +} + +void RISCVELFStreamer::emitInstructionsMappingSymbol() { + if (LastEMS == EMS_Instructions) + return; + emitMappingSymbol("$x"); + LastEMS = EMS_Instructions; +} + +void RISCVELFStreamer::emitMappingSymbol(StringRef Name) { + auto *Symbol = cast(getContext().getOrCreateSymbol( + Name + "." + Twine(MappingSymbolCounter++))); + emitLabel(Symbol); + Symbol->setType(ELF::STT_NOTYPE); + Symbol->setBinding(ELF::STB_LOCAL); +} + +void RISCVELFStreamer::changeSection(MCSection *Section, + const MCExpr *Subsection) { + // We have to keep track of the mapping symbol state of any sections we + // use. Each one should start off as EMS_None, which is provided as the + // default constructor by DenseMap::lookup. + LastMappingSymbols[getPreviousSection().first] = LastEMS; + LastEMS = LastMappingSymbols.lookup(Section); + + MCELFStreamer::changeSection(Section, Subsection); +} + +void RISCVELFStreamer::emitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + emitInstructionsMappingSymbol(); + MCELFStreamer::emitInstruction(Inst, STI); +} + +void RISCVELFStreamer::emitBytes(StringRef Data) { + emitDataMappingSymbol(); + MCELFStreamer::emitBytes(Data); +} + +void RISCVELFStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue, + SMLoc Loc) { + emitDataMappingSymbol(); + MCELFStreamer::emitFill(NumBytes, FillValue, Loc); +} + +void RISCVELFStreamer::emitValueImpl(const MCExpr *Value, unsigned Size, + SMLoc Loc) { + emitDataMappingSymbol(); + MCELFStreamer::emitValueImpl(Value, Size, Loc); } namespace llvm { diff --git a/llvm/test/MC/RISCV/mapping-across-sections.s b/llvm/test/MC/RISCV/mapping-across-sections.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/mapping-across-sections.s @@ -0,0 +1,33 @@ +# RUN: llvm-mc -triple=riscv32 -filetype=obj < %s | llvm-readelf -Ss - | FileCheck %s +# RUN: llvm-mc -triple=riscv64 -filetype=obj < %s | llvm-readelf -Ss - | FileCheck %s + + .text + nop + +# .wibble should *not* inherit .text's mapping symbol. It's a completely +# different section. + .section .wibble + nop + +# A section should be able to start with a $d. + .section .starts_data + .word 42 + +# Changing back to .text should not emit a redundant $x. + .text + nop + +# With all those constraints, we want: +# + .text to have $x at 0 and no others +# + .wibble to have $x at 0 +# + .starts_data to have $d at 0 + +## Capture section indices. +# CHECK: [[#TEXT:]]] .text +# CHECK: [[#WIBBLE:]]] .wibble +# CHECK: [[#STARTS_DATA:]]] .starts_data + +# CHECK: Value Size Type Bind Vis Ndx Name +# CHECK: 00000000 0 NOTYPE LOCAL DEFAULT [[#TEXT]] $x +# CHECK: 00000000 0 NOTYPE LOCAL DEFAULT [[#WIBBLE]] $x +# CHECK: 00000000 0 NOTYPE LOCAL DEFAULT [[#STARTS_DATA]] $d diff --git a/llvm/test/MC/RISCV/mapping-within-section.s b/llvm/test/MC/RISCV/mapping-within-section.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/mapping-within-section.s @@ -0,0 +1,27 @@ +# RUN: llvm-mc -triple=riscv32 -filetype=obj %s | llvm-readelf -Ss - | FileCheck %s +# RUN: llvm-mc -triple=riscv64 -filetype=obj %s | llvm-readelf -Ss - | FileCheck %s + + .text +# $x at 0x0000 + nop +# $d at 0x0004 + .ascii "012" + .byte 1 + .hword 2 + .word 4 + .single 4.0 + .double 8.0 + .space 10 + .zero 3 + .fill 10, 2, 42 + .org 100, 12 +# $x at 0x0064 + nop + +## Capture section index. +# CHECK: [[#TEXT:]]] .text + +# CHECK: Value Size Type Bind Vis Ndx Name +# CHECK: 00000000 0 NOTYPE LOCAL DEFAULT [[#TEXT]] $x +# CHECK: 00000004 0 NOTYPE LOCAL DEFAULT [[#TEXT]] $d +# CHECK: 00000064 0 NOTYPE LOCAL DEFAULT [[#TEXT]] $x