Index: include/llvm/MC/MCELFStreamer.h =================================================================== --- include/llvm/MC/MCELFStreamer.h +++ include/llvm/MC/MCELFStreamer.h @@ -42,6 +42,7 @@ void InitSections(bool NoExecStack) override; void ChangeSection(MCSection *Section, const MCExpr *Subsection) override; void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; + void EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F) override; void EmitAssemblerFlag(MCAssemblerFlag Flag) override; void EmitThumbFunc(MCSymbol *Func) override; void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override; Index: include/llvm/MC/MCObjectStreamer.h =================================================================== --- include/llvm/MC/MCObjectStreamer.h +++ include/llvm/MC/MCObjectStreamer.h @@ -90,6 +90,7 @@ /// @{ void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; + virtual void EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F); void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; void EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc = SMLoc()) override; Index: lib/MC/MCELFStreamer.cpp =================================================================== --- lib/MC/MCELFStreamer.cpp +++ lib/MC/MCELFStreamer.cpp @@ -103,6 +103,16 @@ Symbol->setType(ELF::STT_TLS); } +void MCELFStreamer::EmitLabel(MCSymbol *S, SMLoc Loc, MCFragment *F) { + auto *Symbol = cast(S); + MCObjectStreamer::EmitLabel(Symbol, Loc, F); + + const MCSectionELF &Section = + static_cast(*getCurrentSectionOnly()); + if (Section.getFlags() & ELF::SHF_TLS) + Symbol->setType(ELF::STT_TLS); +} + void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { // Let the target do whatever target specific stuff it needs to do. getAssembler().getBackend().handleAssemblerFlag(Flag); Index: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -171,6 +171,14 @@ } } +void MCObjectStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F) { + MCStreamer::EmitLabel(Symbol, Loc); + getAssembler().registerSymbol(*Symbol); + auto *DF = dyn_cast_or_null(getCurrentFragment()); + if (DF) + Symbol->setFragment(DF); +} + void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) { int64_t IntValue; if (Value->evaluateAsAbsolute(IntValue, getAssembler())) { @@ -490,8 +498,8 @@ MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); - DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), - Value, FK_GPRel_4)); + DF->getFixups().push_back( + MCFixup::create(DF->getContents().size(), Value, FK_GPRel_4)); DF->getContents().resize(DF->getContents().size() + 4, 0); } @@ -500,8 +508,8 @@ MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); - DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), - Value, FK_GPRel_4)); + DF->getFixups().push_back( + MCFixup::create(DF->getContents().size(), Value, FK_GPRel_4)); DF->getContents().resize(DF->getContents().size() + 8, 0); } Index: lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -464,13 +464,17 @@ void emitUnwindRaw(int64_t Offset, const SmallVectorImpl &Opcodes); void ChangeSection(MCSection *Section, const MCExpr *Subsection) override { - // 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); - + LastMappingSymbols[getPreviousSection().first] = + std::make_pair(LastEMS, std::move(LastEMSInfo)); MCELFStreamer::ChangeSection(Section, Subsection); + auto LastMappingSymbol = LastMappingSymbols.find(Section); + if (LastMappingSymbol != LastMappingSymbols.end()) { + LastEMS = LastMappingSymbol->second.first; + LastEMSInfo = std::move(LastMappingSymbol->second.second); + return; + } + LastEMS = EMS_None; + LastEMSInfo.reset(new ElfMappingSymbolInfo(SMLoc(), nullptr, 0)); } /// This function is the one used to emit instruction data into the ELF @@ -528,10 +532,19 @@ /// ARM streamer overrides it to add the appropriate mapping symbol ($d) if /// necessary. void EmitBytes(StringRef Data) override { + DelayEmitDataMappingSymbol(); EmitDataMappingSymbol(); MCELFStreamer::EmitBytes(Data); } + void EmitDataMappingSymbolForAnySkipped() { + if (!LastEMSInfo->hasInfo()) + return; + ElfMappingSymbolInfo *EMS = LastEMSInfo.get(); + EmitMappingSymbol("$d", EMS->Loc, EMS->F, EMS->Offset); + EMS->resetInfo(); + } + /// This is one of the functions used to emit data into an ELF section, so the /// ARM streamer overrides it to add the appropriate mapping symbol ($d) if /// necessary. @@ -542,10 +555,32 @@ return; } + DelayEmitDataMappingSymbol(); EmitDataMappingSymbol(); MCELFStreamer::EmitValueImpl(Value, Size, Loc); } + /// Delay emitting the data mapping symbol. Whenever we have data and code + /// mixed in the same section, and data appears before code, the streamer + /// would not know if there is actually a mix of data and code. We can do two + /// things here, we can immediately emit a data mapping symbol but if there + /// was no instructions mixed with data, this mapping symbol should not have + /// existed. Here we delay the emitting of the data mapping symbol until we + /// see a real instruction. For this reason the function records the + /// information thats needed to emit the symbol later in ElfMappingSymbolInfo + /// structure. + void DelayEmitDataMappingSymbol() { + // Delay emitting the label only if the streamer is in the initial state. + if (LastEMSInfo->hasInfo() || LastEMS != EMS_None) + return; + ElfMappingSymbolInfo *EMS = LastEMSInfo.get(); + EMS->Loc = SMLoc(); + EMS->F = getCurrentFragment(); + auto *DF = dyn_cast_or_null(EMS->F); + if (DF) + EMS->Offset = DF->getContents().size(); + } + void EmitAssemblerFlag(MCAssemblerFlag Flag) override { MCELFStreamer::EmitAssemblerFlag(Flag); @@ -573,20 +608,45 @@ EMS_Data }; + struct ElfMappingSymbolInfo { + explicit ElfMappingSymbolInfo(SMLoc Loc, MCFragment *F, uint64_t O) + : Loc(Loc), F(F), Offset(O) {} + void resetInfo() { + F = nullptr; + Offset = 0; + } + bool hasInfo() { return F != nullptr; } + SMLoc Loc; + MCFragment *F; + uint64_t Offset; + }; + void EmitDataMappingSymbol() { - if (LastEMS == EMS_Data) return; - EmitMappingSymbol("$d"); + if (LastEMS == EMS_Data) + return; + // If the section has executable permissions, the streamer will emit a data + // mapping symbol to denote that there is a mix of data in a section with + // executable permissions. + if (LastEMS != EMS_None || + (cast(getCurrentSectionOnly()))->UseCodeAlign()) { + LastEMSInfo->resetInfo(); + EmitMappingSymbol("$d"); + } LastEMS = EMS_Data; } void EmitThumbMappingSymbol() { - if (LastEMS == EMS_Thumb) return; + if (LastEMS == EMS_Thumb) + return; + EmitDataMappingSymbolForAnySkipped(); EmitMappingSymbol("$t"); LastEMS = EMS_Thumb; } void EmitARMMappingSymbol() { - if (LastEMS == EMS_ARM) return; + if (LastEMS == EMS_ARM) + return; + EmitDataMappingSymbolForAnySkipped(); EmitMappingSymbol("$a"); LastEMS = EMS_ARM; } @@ -601,6 +661,17 @@ Symbol->setExternal(false); } + void EmitMappingSymbol(StringRef Name, SMLoc Loc, MCFragment *F, + uint64_t Offset) { + auto *Symbol = cast(getContext().getOrCreateSymbol( + Name + "." + Twine(MappingSymbolCounter++))); + EmitLabel(Symbol, Loc, F); + Symbol->setType(ELF::STT_NOTYPE); + Symbol->setBinding(ELF::STB_LOCAL); + Symbol->setExternal(false); + Symbol->setOffset(Offset); + } + void EmitThumbFunc(MCSymbol *Func) override { getAssembler().setIsThumbFunc(Func); EmitSymbolAttribute(Func, MCSA_ELF_TypeFunction); @@ -626,8 +697,13 @@ bool IsThumb; int64_t MappingSymbolCounter = 0; - DenseMap LastMappingSymbols; - ElfMappingSymbol LastEMS = EMS_None; + DenseMap>> + LastMappingSymbols; + + ElfMappingSymbol LastEMS = EMS_Data; + + std::unique_ptr LastEMSInfo; // ARM Exception Handling Frame Information MCSymbol *ExTab; Index: test/MC/ARM/Inputs/1.s =================================================================== --- /dev/null +++ test/MC/ARM/Inputs/1.s @@ -0,0 +1,3 @@ + .section .foobar,"ax",%progbits + nop + .word 32 Index: test/MC/ARM/Inputs/2.s =================================================================== --- /dev/null +++ test/MC/ARM/Inputs/2.s @@ -0,0 +1,3 @@ + .section .foobar,"",%progbits + nop + .word 32 Index: test/MC/ARM/Inputs/3.s =================================================================== --- /dev/null +++ test/MC/ARM/Inputs/3.s @@ -0,0 +1,3 @@ + .section .foobar,"aw",%progbits + nop + .word 32 Index: test/MC/ARM/Inputs/4.s =================================================================== --- /dev/null +++ test/MC/ARM/Inputs/4.s @@ -0,0 +1,2 @@ + .section .foobar,"",%progbits + .word 32 Index: test/MC/ARM/Inputs/5.s =================================================================== --- /dev/null +++ test/MC/ARM/Inputs/5.s @@ -0,0 +1,2 @@ + .section .foobar,"aw",%progbits + .word 32 Index: test/MC/ARM/Inputs/6.s =================================================================== --- /dev/null +++ test/MC/ARM/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 Index: test/MC/ARM/Inputs/7.s =================================================================== --- /dev/null +++ test/MC/ARM/Inputs/7.s @@ -0,0 +1,3 @@ + .section .foobar,"aw",%progbits + .word 32 + nop Index: test/MC/ARM/Inputs/attr.s =================================================================== --- /dev/null +++ test/MC/ARM/Inputs/attr.s @@ -0,0 +1,5 @@ + .text + .syntax unified + .eabi_attribute 67, "2.09" @ Tag_conformance + .cpu arm7tdmi + .eabi_attribute 6, 2 @ Tag_CPU_arch Index: test/MC/ARM/Inputs/ident.s =================================================================== --- /dev/null +++ test/MC/ARM/Inputs/ident.s @@ -0,0 +1 @@ + .ident "LLVM ARM Compiler" Index: test/MC/ARM/data-in-code.ll =================================================================== --- test/MC/ARM/data-in-code.ll +++ test/MC/ARM/data-in-code.ll @@ -60,23 +60,6 @@ ;; ARM-NEXT: Other: ;; ARM-NEXT: Section: [[MIXED_SECT]] -;; ARM: Symbol { -;; ARM: Name: $d -;; ARM-NEXT: Value: 0x0 -;; ARM-NEXT: Size: 0 -;; ARM-NEXT: Binding: Local (0x0) -;; ARM-NEXT: Type: None (0x0) -;; ARM-NEXT: Other: 0 -;; ARM-NEXT: Section: .ARM.exidx -;; ARM-NEXT: } - -;; ARM: Symbol { -;; ARM: Name: $d -;; ARM-NEXT: Value: 0 -;; ARM-NEXT: Size: 0 -;; ARM-NEXT: Binding: Local -;; ARM-NEXT: Type: None - ;; ARM-NOT: ${{[atd]}} ;; TMB: Symbol { Index: test/MC/ARM/mappingsymbols.s =================================================================== --- /dev/null +++ test/MC/ARM/mappingsymbols.s @@ -0,0 +1,48 @@ +# Check section containing code and data with permission executable for the section. +@ RUN: llvm-mc -triple armv7-none-linux -filetype=obj -o %t.o %p/Inputs/1.s +@ RUN: llvm-readobj -elf-output-style=GNU -symbols %t.o | FileCheck %s + +# Check section containing code and data with no permissions for the section. +@ RUN: llvm-mc -triple armv7-none-linux -filetype=obj -o %t.o %p/Inputs/2.s +@ RUN: llvm-readobj -elf-output-style=GNU -symbols %t.o | FileCheck %s + +# Check section containing code and data with read/write permissions for the section. +@ RUN: llvm-mc -triple armv7-none-linux -filetype=obj -o %t.o %p/Inputs/3.s +@ RUN: llvm-readobj -elf-output-style=GNU -symbols %t.o | FileCheck %s + +# Check section containing data with no permissions for the section. +@ RUN: llvm-mc -triple armv7-none-linux -filetype=obj -o %t.o %p/Inputs/4.s +@ RUN: llvm-readobj -elf-output-style=GNU -symbols %t.o | FileCheck %s -check-prefix=MAPPINGSYMBOLS + +# Check section containing only data with read/write permissions for the section. +@ RUN: llvm-mc -triple armv7-none-linux -filetype=obj -o %t.o %p/Inputs/5.s +@ RUN: llvm-readobj -elf-output-style=GNU -symbols %t.o | FileCheck %s -check-prefix=MAPPINGSYMBOLS + +# Check section containing the ident string with no permissions for the section. +@ RUN: llvm-mc -triple armv7-none-linux -filetype=obj -o %t.o %p/Inputs/ident.s +@ RUN: llvm-readobj -elf-output-style=GNU -symbols %t.o | FileCheck %s -check-prefix=MAPPINGSYMBOLS + +# Check section containing the attributes with no permissions for the section. +@ RUN: llvm-mc -triple armv7-none-linux -filetype=obj -o %t.o %p/Inputs/attr.s +@ RUN: llvm-readobj -elf-output-style=GNU -symbols %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 armv7-none-linux -filetype=obj -o %t.o %p/Inputs/6.s +@ RUN: llvm-readobj -elf-output-style=GNU -symbols %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 armv7-none-linux -filetype=obj -o %t.o %p/Inputs/7.s +@ RUN: llvm-readobj -elf-output-style=GNU -symbols %t.o | FileCheck %s + +#CHECK: $a +#CHECK: $d + +#MIX: $a +#MIX: $a +#MIX: $d +#MIX: $d + +#MAPPINGSYMBOLS-NOT: $a +#MAPPINGSYMBOLS-NOT: $d Index: test/MC/ARM/multi-section-mapping.s =================================================================== --- test/MC/ARM/multi-section-mapping.s +++ test/MC/ARM/multi-section-mapping.s @@ -29,7 +29,6 @@ @ CHECK: 00000000 .text 00000000 $a @ CHECK-NEXT: 00000000 .wibble 00000000 $a -@ CHECK-NEXT: 00000000 .starts_data 00000000 $d @ CHECK-NEXT: 00000000 .starts_thumb 00000000 $t @ CHECK-NOT: ${{[adt]}} Index: test/Object/ARM/nm-mapping-symbol.s =================================================================== --- test/Object/ARM/nm-mapping-symbol.s +++ test/Object/ARM/nm-mapping-symbol.s @@ -7,5 +7,5 @@ // CHECK: Name: $d.0 // NM-NOT: $d.0 - .section .foobar,"",%progbits + .section .foobar,"ax",%progbits .asciz "foo"