Index: include/lld/Core/DefinedAtom.h =================================================================== --- include/lld/Core/DefinedAtom.h +++ include/lld/Core/DefinedAtom.h @@ -193,6 +193,15 @@ dynamicExportAlways, }; + // Attributes describe a code model used by the atom. + enum CodeModel { + codeNA, // no specific code model + codeMipsPIC, // PIC function in a PIC / non-PIC mixed file + codeMipsMicro, // microMIPS instruction encoding + codeMipsMicroPIC, // microMIPS instruction encoding + PIC + codeMips16, // MIPS-16 instruction encoding + }; + struct Alignment { Alignment(int p2, int m = 0) : powerOf2(p2) @@ -265,6 +274,9 @@ return dynamicExportNormal; } + /// \brief Code model used by the atom. + virtual CodeModel codeModel() const { return codeNA; } + /// \brief Returns the OS memory protections required for this atom's content /// at runtime. /// Index: lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h +++ lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h @@ -17,6 +17,7 @@ namespace lld { namespace elf { +template class MipsSymbolTable; template class MipsDynamicSymbolTable; template class MipsTargetLayout; @@ -39,6 +40,7 @@ return std::error_code(); } + LLD_UNIQUE_BUMP_PTR(SymbolTable) createSymbolTable() override; LLD_UNIQUE_BUMP_PTR(DynamicTable) createDynamicTable() override; LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) @@ -73,6 +75,13 @@ _writeHelper.finalizeMipsRuntimeAtomValues(); } +template +LLD_UNIQUE_BUMP_PTR(SymbolTable) + MipsDynamicLibraryWriter::createSymbolTable() { + return LLD_UNIQUE_BUMP_PTR(SymbolTable)(new ( + this->_alloc) MipsSymbolTable(_mipsContext)); +} + /// \brief create dynamic table template LLD_UNIQUE_BUMP_PTR(DynamicTable) Index: lib/ReaderWriter/ELF/Mips/MipsELFFile.h =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsELFFile.h +++ lib/ReaderWriter/ELF/Mips/MipsELFFile.h @@ -60,6 +60,21 @@ const MipsELFFile& file() const override { return static_cast &>(this->_owningFile); } + + DefinedAtom::CodeModel codeModel() const override { + switch (this->_symbol->st_other & llvm::ELF::STO_MIPS_MIPS16) { + case llvm::ELF::STO_MIPS_MIPS16: + return DefinedAtom::codeMips16; + case llvm::ELF::STO_MIPS_PIC: + return DefinedAtom::codeMipsPIC; + case llvm::ELF::STO_MIPS_MICROMIPS: + return DefinedAtom::codeMipsMicro; + case llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC: + return DefinedAtom::codeMipsMicroPIC; + default: + return DefinedAtom::codeNA; + } + } }; template class MipsELFFile : public ELFFile { Index: lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h +++ lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h @@ -39,6 +39,7 @@ return std::error_code(); } + LLD_UNIQUE_BUMP_PTR(SymbolTable) createSymbolTable() override; LLD_UNIQUE_BUMP_PTR(DynamicTable) createDynamicTable() override; LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) @@ -113,6 +114,13 @@ _writeHelper.finalizeMipsRuntimeAtomValues(); } +template +LLD_UNIQUE_BUMP_PTR(SymbolTable) + MipsExecutableWriter::createSymbolTable() { + return LLD_UNIQUE_BUMP_PTR(SymbolTable)(new ( + this->_alloc) MipsSymbolTable(_mipsContext)); +} + /// \brief create dynamic table template LLD_UNIQUE_BUMP_PTR(DynamicTable) Index: lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h +++ lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h @@ -135,6 +135,48 @@ std::unique_ptr _relocationHandler; }; +template class MipsSymbolTable : public SymbolTable { +public: + typedef llvm::object::Elf_Sym_Impl Elf_Sym; + + MipsSymbolTable(const MipsLinkingContext &ctx) + : SymbolTable(ctx, ".symtab", + DefaultLayout::ORDER_SYMBOL_TABLE) {} + + void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, + int64_t addr) override { + SymbolTable::addDefinedAtom(sym, da, addr); + + switch (da->codeModel()) { + case DefinedAtom::codeMipsMicro: + sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS; + break; + case DefinedAtom::codeMipsMicroPIC: + sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC; + break; + default: + break; + } + } + + void finalize(bool sort = true) override { + SymbolTable::finalize(sort); + + for (auto &ste : this->_symbolTable) { + if (!ste._atom) + continue; + if (const auto *da = dyn_cast(ste._atom)) { + if (da->codeModel() == DefinedAtom::codeMipsMicro || + da->codeModel() == DefinedAtom::codeMipsMicroPIC) { + // Adjust dynamic microMIPS symbol value. That allows a dynamic + // linker to recognize and handle this symbol correctly. + ste._symbol.st_value = ste._symbol.st_value | 1; + } + } + } + } +}; + template class MipsDynamicSymbolTable : public DynamicSymbolTable { public: @@ -157,23 +199,30 @@ } void finalize() override { + DynamicSymbolTable::finalize(); + const auto &pltSection = _targetLayout.getPLTSection(); - // Under some conditions a dynamic symbol table record should hold a symbol - // value of the corresponding PLT entry. For details look at the PLT entry - // creation code in the class MipsRelocationPass. Let's update atomLayout - // fields for such symbols. for (auto &ste : this->_symbolTable) { if (!ste._atom) continue; if (auto *layout = pltSection.findPLTLayout(ste._atom)) { + // Under some conditions a dynamic symbol table record should hold + // a symbol value of the corresponding PLT entry. For details look + // at the PLT entry creation code in the class MipsRelocationPass. + // Let's update atomLayout fields for such symbols. assert(!ste._atomLayout); ste._symbol.st_value = layout->_virtualAddr; ste._symbol.st_other |= ELF::STO_MIPS_PLT; + } else if (const auto *da = dyn_cast(ste._atom)) { + if (da->codeModel() == DefinedAtom::codeMipsMicro || + da->codeModel() == DefinedAtom::codeMipsMicroPIC) { + // Adjust dynamic microMIPS symbol value. That allows a dynamic + // linker to recognize and handle this symbol correctly. + ste._symbol.st_value = ste._symbol.st_value | 1; + } } } - - DynamicSymbolTable::finalize(); } private: Index: lib/ReaderWriter/ELF/OutputELFWriter.h =================================================================== --- lib/ReaderWriter/ELF/OutputELFWriter.h +++ lib/ReaderWriter/ELF/OutputELFWriter.h @@ -100,6 +100,9 @@ // This is a hook for creating default dynamic entries virtual void createDefaultDynamicEntries() {} + /// \brief Create symbol table. + virtual LLD_UNIQUE_BUMP_PTR(SymbolTable) createSymbolTable(); + /// \brief create dynamic table. virtual LLD_UNIQUE_BUMP_PTR(DynamicTable) createDynamicTable(); @@ -284,8 +287,7 @@ _layout.setHeader(_elfHeader.get()); _layout.setProgramHeader(_programHeader.get()); - _symtab.reset(new (_alloc) SymbolTable( - _context, ".symtab", DefaultLayout::ORDER_SYMBOL_TABLE)); + _symtab = std::move(this->createSymbolTable()); _strtab.reset(new (_alloc) StringTable( _context, ".strtab", DefaultLayout::ORDER_STRING_TABLE)); _shstrtab.reset(new (_alloc) StringTable( @@ -336,6 +338,13 @@ } } +template +LLD_UNIQUE_BUMP_PTR(SymbolTable) + OutputELFWriter::createSymbolTable() { + return LLD_UNIQUE_BUMP_PTR(SymbolTable)(new (_alloc) SymbolTable( + this->_context, ".symtab", DefaultLayout::ORDER_SYMBOL_TABLE)); +} + /// \brief create dynamic table template LLD_UNIQUE_BUMP_PTR(DynamicTable) Index: lib/ReaderWriter/Native/NativeFileFormat.h =================================================================== --- lib/ReaderWriter/Native/NativeFileFormat.h +++ lib/ReaderWriter/Native/NativeFileFormat.h @@ -155,6 +155,7 @@ uint8_t dynamicExport; uint8_t permissions; uint8_t alias; + uint8_t codeModel; }; Index: lib/ReaderWriter/Native/ReaderNative.cpp =================================================================== --- lib/ReaderWriter/Native/ReaderNative.cpp +++ lib/ReaderWriter/Native/ReaderNative.cpp @@ -90,6 +90,10 @@ return (DynamicExport)attributes().dynamicExport; } + DefinedAtom::CodeModel codeModel() const override { + return DefinedAtom::CodeModel(attributes().codeModel); + } + DefinedAtom::ContentPermissions permissions() const override { return (DefinedAtom::ContentPermissions)(attributes().permissions); } Index: lib/ReaderWriter/Native/WriterNative.cpp =================================================================== --- lib/ReaderWriter/Native/WriterNative.cpp +++ lib/ReaderWriter/Native/WriterNative.cpp @@ -426,6 +426,7 @@ = atom.sectionChoice() << 4 | atom.sectionPosition(); attrs.deadStrip = atom.deadStrip(); attrs.dynamicExport = atom.dynamicExport(); + attrs.codeModel = atom.codeModel(); attrs.permissions = atom.permissions(); return attrs; } Index: lib/ReaderWriter/YAML/ReaderWriterYAML.cpp =================================================================== --- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -386,6 +386,16 @@ } }; +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, lld::DefinedAtom::CodeModel &value) { + io.enumCase(value, "none", lld::DefinedAtom::codeNA); + io.enumCase(value, "mips-pic", lld::DefinedAtom::codeMipsPIC); + io.enumCase(value, "mips-micro", lld::DefinedAtom::codeMipsMicro); + io.enumCase(value, "mips-micro-pic", lld::DefinedAtom::codeMipsMicroPIC); + io.enumCase(value, "mips-16", lld::DefinedAtom::codeMips16); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) { @@ -808,6 +818,7 @@ _alignment(atom->alignment()), _sectionChoice(atom->sectionChoice()), _sectionPosition(atom->sectionPosition()), _deadStrip(atom->deadStrip()), _dynamicExport(atom->dynamicExport()), + _codeModel(atom->codeModel()), _permissions(atom->permissions()), _size(atom->size()), _sectionName(atom->customSectionName()) { for (const lld::Reference *r : *atom) @@ -858,6 +869,7 @@ SectionPosition sectionPosition() const override { return _sectionPosition; } DeadStripKind deadStrip() const override { return _deadStrip; } DynamicExport dynamicExport() const override { return _dynamicExport; } + CodeModel codeModel() const override { return _codeModel; } ContentPermissions permissions() const override { return _permissions; } void setGroupChild(bool val) { _isGroupChild = val; } bool isGroupChild() const { return _isGroupChild; } @@ -903,6 +915,7 @@ SectionPosition _sectionPosition; DeadStripKind _deadStrip; DynamicExport _dynamicExport; + CodeModel _codeModel; ContentPermissions _permissions; uint32_t _ordinal; std::vector _content; @@ -950,6 +963,7 @@ DefinedAtom::deadStripNormal); io.mapOptional("dynamic-export", keys->_dynamicExport, DefinedAtom::dynamicExportNormal); + io.mapOptional("code-model", keys->_codeModel, DefinedAtom::codeNA); // default permissions based on content type io.mapOptional("permissions", keys->_permissions, DefinedAtom::permissions( Index: test/core/code-model-attributes.objtxt =================================================================== --- /dev/null +++ test/core/code-model-attributes.objtxt @@ -0,0 +1,50 @@ +# RUN: lld -core %s | FileCheck %s + +# +# Test that code model attributes are preserved +# + +--- +defined-atoms: + - name: _def +--- +defined-atoms: + - name: _none + code-model: none +--- +defined-atoms: + - name: _mips_pic + code-model: mips-pic +--- +defined-atoms: + - name: _mips_micro + code-model: mips-micro +--- +defined-atoms: + - name: _mips_micro_pic + code-model: mips-micro-pic +--- +defined-atoms: + - name: _mips_16 + code-model: mips-16 +... + +# CHECK: name: _def +# CHECK-NOT: code-model: mips-pic +# CHECK-NOT: code-model: mips-micro +# CHECK-NOT: code-model: mips-micro-pic +# CHECK-NOT: code-model: mips-16 +# CHECK: name: _none +# CHECK-NOT: code-model: mips-pic +# CHECK-NOT: code-model: mips-micro +# CHECK-NOT: code-model: mips-micro-pic +# CHECK-NOT: code-model: mips-16 +# CHECK: name: _mips_pic +# CHECK: code-model: mips-pic +# CHECK: name: _mips_micro +# CHECK: code-model: mips-micro +# CHECK: name: _mips_micro_pic +# CHECK: code-model: mips-micro-pic +# CHECK: name: _mips_16 +# CHECK: code-model: mips-16 +# CHECK: ... Index: test/elf/Mips/st-other.test =================================================================== --- /dev/null +++ test/elf/Mips/st-other.test @@ -0,0 +1,90 @@ +# Check STO_MICROMIPS flag handling. microMIPS symbol records in a dynamic +# symbol table should not have STO_MICROMIPS flag but their value field +# must be odd. microMIPS symbol records in a regular symbol table should +# have the STO_MICROMIPS flag. + +# RUN: yaml2obj -format=elf %s > %t-micro.o + +# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-micro.o +# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck -check-prefix=SO %s + +# RUN: lld -flavor gnu -target mipsel -e S0 -o %t.exe %t-micro.o +# RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=EXE-SYM %s +# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=EXE-DSYM %s + +# SO: Symbol { +# SO: Name: S0@ (1) +# SO-NEXT: Value: 0xEC +# SO-NEXT: Size: 4 +# SO-NEXT: Binding: Global (0x1) +# SO-NEXT: Type: Function (0x2) +# SO-NEXT: Other: 0 +# SO-NEXT: Section: .text (0x4) +# SO-NEXT: } + +# SO: Symbol { +# SO: Name: S1@ (4) +# SO-NEXT: Value: 0xF1 +# SO-NEXT: Size: 4 +# SO-NEXT: Binding: Global (0x1) +# SO-NEXT: Type: Function (0x2) +# SO-NEXT: Other: 0 +# SO-NEXT: Section: .text (0x4) +# SO-NEXT: } + +# EXE-SYM: Symbol { +# EXE-SYM: Name: S0 (1) +# EXE-SYM-NEXT: Value: 0x400108 +# EXE-SYM-NEXT: Size: 4 +# EXE-SYM-NEXT: Binding: Global (0x1) +# EXE-SYM-NEXT: Type: Function (0x2) +# EXE-SYM-NEXT: Other: 0 +# EXE-SYM-NEXT: Section: .text (0x5) +# EXE-SYM-NEXT: } + +# EXE-SYM: Symbol { +# EXE-SYM: Name: S1 (4) +# EXE-SYM-NEXT: Value: 0x40010D +# EXE-SYM-NEXT: Size: 4 +# EXE-SYM-NEXT: Binding: Global (0x1) +# EXE-SYM-NEXT: Type: Function (0x2) +# EXE-SYM-NEXT: Other: 128 +# EXE-SYM-NEXT: Section: .text (0x5) +# EXE-SYM-NEXT: } + +# EXE-DSYM-NOT: Name: S1 (4) + +# micro.o +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS + Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS] + +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x04 + Size: 0x08 + +Symbols: + Global: + - Name: S0 + Type: STT_FUNC + Section: .text + Size: 0x04 + Value: 0x00 + Visibility: STV_DEFAULT + Other: [ ] + + - Name: S1 + Type: STT_FUNC + Section: .text + Size: 0x04 + Value: 0x04 + Visibility: STV_DEFAULT + Other: [ STO_MIPS_MICROMIPS ] +...