Index: lld/trunk/include/lld/Core/DefinedAtom.h =================================================================== --- lld/trunk/include/lld/Core/DefinedAtom.h +++ lld/trunk/include/lld/Core/DefinedAtom.h @@ -201,6 +201,7 @@ codeMipsMicro, // microMIPS instruction encoding codeMipsMicroPIC, // microMIPS instruction encoding + PIC codeMips16, // MIPS-16 instruction encoding + codeARMThumb, // ARM Thumb instruction set }; struct Alignment { Index: lld/trunk/lib/ReaderWriter/ELF/ARM/ARMELFFile.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/ARM/ARMELFFile.h +++ lld/trunk/lib/ReaderWriter/ELF/ARM/ARMELFFile.h @@ -17,6 +17,39 @@ class ARMLinkingContext; +template class ARMELFDefinedAtom : public ELFDefinedAtom { + typedef llvm::object::Elf_Sym_Impl Elf_Sym; + typedef llvm::object::Elf_Shdr_Impl Elf_Shdr; + +public: + ARMELFDefinedAtom(const ELFFile &file, StringRef symbolName, + StringRef sectionName, const Elf_Sym *symbol, + const Elf_Shdr *section, ArrayRef contentData, + unsigned int referenceStart, unsigned int referenceEnd, + std::vector *> &referenceList) + : ELFDefinedAtom(file, symbolName, sectionName, symbol, section, + contentData, referenceStart, referenceEnd, + referenceList) {} + + bool isThumbFunc(const Elf_Sym *symbol) const { + return symbol->getType() == llvm::ELF::STT_FUNC && + (static_cast(symbol->st_value) & 0x1); + } + + /// Correct st_value for symbols addressing Thumb instructions + /// by removing its zero bit. + uint64_t getSymbolValue(const Elf_Sym *symbol) const override { + const auto value = static_cast(symbol->st_value); + return isThumbFunc(symbol) ? value & ~0x1 : value; + } + + DefinedAtom::CodeModel codeModel() const override { + if (isThumbFunc(this->_symbol)) + return DefinedAtom::codeARMThumb; + return DefinedAtom::codeNA; + } +}; + template class ARMELFFile : public ELFFile { public: ARMELFFile(std::unique_ptr mb, bool atomizeStrings) @@ -27,6 +60,29 @@ return std::unique_ptr>( new ARMELFFile(std::move(mb), atomizeStrings)); } + +private: + typedef llvm::object::Elf_Sym_Impl Elf_Sym; + typedef llvm::object::Elf_Shdr_Impl Elf_Shdr; + + /// Correct st_value for symbols addressing Thumb instructions + /// by removing its zero bit. + uint64_t getSymbolValue(const Elf_Sym *symbol) const override { + const auto value = static_cast(symbol->st_value); + return symbol->getType() == llvm::ELF::STT_FUNC ? value & ~0x1 : value; + } + + /// Process the Defined symbol and create an atom for it. + ErrorOr *> handleDefinedSymbol(StringRef symName, + StringRef sectionName, + const Elf_Sym *sym, const Elf_Shdr *sectionHdr, + ArrayRef contentData, + unsigned int referenceStart, unsigned int referenceEnd, + std::vector *> &referenceList) override { + return new (this->_readerStorage) ARMELFDefinedAtom( + *this, symName, sectionName, sym, sectionHdr, contentData, + referenceStart, referenceEnd, referenceList); + } }; template class ARMDynamicFile : public DynamicFile { Index: lld/trunk/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h +++ lld/trunk/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h @@ -12,6 +12,7 @@ #include "ExecutableWriter.h" #include "ARMLinkingContext.h" #include "ARMTargetHandler.h" +#include "ARMSymbolTable.h" namespace lld { namespace elf { @@ -35,6 +36,9 @@ ExecutableWriter::addDefaultAtoms(); } + /// \brief Create symbol table. + LLD_UNIQUE_BUMP_PTR(SymbolTable) createSymbolTable() override; + private: ARMLinkingContext &_context; ARMTargetLayout &_armLayout; @@ -53,6 +57,13 @@ return true; } +template +LLD_UNIQUE_BUMP_PTR(SymbolTable) + ARMExecutableWriter::createSymbolTable() { + return LLD_UNIQUE_BUMP_PTR(SymbolTable)( + new (this->_alloc) ARMSymbolTable(this->_context)); +} + } // namespace elf } // namespace lld Index: lld/trunk/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h +++ lld/trunk/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h @@ -0,0 +1,46 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h ------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H +#define LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H + +namespace lld { +namespace elf { + +/// \brief The SymbolTable class represents the symbol table in a ELF file +template +class ARMSymbolTable : public SymbolTable { +public: + typedef llvm::object::Elf_Sym_Impl Elf_Sym; + + ARMSymbolTable(const ELFLinkingContext &context); + + void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, + int64_t addr) override; +}; + +template +ARMSymbolTable::ARMSymbolTable(const ELFLinkingContext &context) + : SymbolTable(context, ".symtab", + DefaultLayout::ORDER_SYMBOL_TABLE) {} + +template +void ARMSymbolTable::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, + int64_t addr) { + SymbolTable::addDefinedAtom(sym, da, addr); + + // Set zero bit to distinguish symbols addressing Thumb instructions + if (DefinedAtom::codeARMThumb == da->codeModel()) + sym.st_value = static_cast(sym.st_value) | 0x1; +} + +} // elf +} // lld + +#endif // LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H Index: lld/trunk/lib/ReaderWriter/ELF/Atoms.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/Atoms.h +++ lld/trunk/lib/ReaderWriter/ELF/Atoms.h @@ -281,17 +281,20 @@ } Alignment alignment() const override { + // Obtain proper value of st_value field. + const auto symValue = getSymbolValue(_symbol); + // Unallocated common symbols specify their alignment constraints in // st_value. if ((_symbol->getType() == llvm::ELF::STT_COMMON) || _symbol->st_shndx == llvm::ELF::SHN_COMMON) { - return Alignment(llvm::Log2_64(_symbol->st_value)); + return Alignment(llvm::Log2_64(symValue)); } else if (_section->sh_addralign == 0) { // sh_addralign of 0 means no alignment - return Alignment(0, _symbol->st_value); + return Alignment(0, symValue); } return Alignment(llvm::Log2_64(_section->sh_addralign), - _symbol->st_value % _section->sh_addralign); + symValue % _section->sh_addralign); } // Do we have a choice for ELF? All symbols live in explicit sections. @@ -416,6 +419,13 @@ virtual void setOrdinal(uint64_t ord) { _ordinal = ord; } protected: + /// Returns correct st_value for the symbol depending on the architecture. + /// For most architectures it's just a regular st_value with no changes. + virtual uint64_t getSymbolValue(const Elf_Sym *symbol) const { + return symbol->st_value; + } + +protected: const ELFFile &_owningFile; StringRef _symbolName; StringRef _sectionName; Index: lld/trunk/lib/ReaderWriter/ELF/ELFFile.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/ELFFile.h +++ lld/trunk/lib/ReaderWriter/ELF/ELFFile.h @@ -279,6 +279,12 @@ symbol->st_shndx == llvm::ELF::SHN_COMMON; } + /// Returns correct st_value for the symbol depending on the architecture. + /// For most architectures it's just a regular st_value with no changes. + virtual uint64_t getSymbolValue(const Elf_Sym *symbol) const { + return symbol->st_value; + } + /// Process the common symbol and create an atom for it. virtual ErrorOr *> handleCommonSymbol(StringRef symName, const Elf_Sym *sym) { @@ -573,7 +579,7 @@ if (isAbsoluteSymbol(&*SymI)) { ErrorOr *> absAtom = - handleAbsoluteSymbol(*symbolName, &*SymI, SymI->st_value); + handleAbsoluteSymbol(*symbolName, &*SymI, (int64_t)getSymbolValue(&*SymI)); _absoluteAtoms._atoms.push_back(*absAtom); _symbolToAtomMapping.insert(std::make_pair(&*SymI, *absAtom)); } else if (isUndefinedSymbol(&*SymI)) { @@ -605,8 +611,8 @@ // Sort symbols by position. std::stable_sort(symbols.begin(), symbols.end(), - [](Elf_Sym_Iter a, Elf_Sym_Iter b) { - return a->st_value < b->st_value; + [this](Elf_Sym_Iter a, Elf_Sym_Iter b) { + return getSymbolValue(&*a) < getSymbolValue(&*b); }); ErrorOr sectionName = this->getSectionName(section); @@ -658,7 +664,7 @@ } ArrayRef symbolData((const uint8_t *)sectionContents->data() + - symbol->st_value, + getSymbolValue(&*symbol), contentSize); // If the linker finds that a section has global atoms that are in a @@ -766,12 +772,13 @@ ArrayRef content, range rels) { bool isMips64EL = _objFile->isMips64EL(); + const auto symValue = getSymbolValue(&symbol); for (const auto &rel : rels) { - if (rel.r_offset < symbol.st_value || - symbol.st_value + content.size() <= rel.r_offset) + if (rel.r_offset < symValue || + symValue + content.size() <= rel.r_offset) continue; _references.push_back(new (_readerStorage) ELFReference( - &rel, rel.r_offset - symbol.st_value, kindArch(), + &rel, rel.r_offset - symValue, kindArch(), rel.getType(isMips64EL), rel.getSymbol(isMips64EL))); } } @@ -782,14 +789,15 @@ ArrayRef secContent, range rels) { bool isMips64EL = _objFile->isMips64EL(); + const auto symValue = getSymbolValue(&symbol); for (const auto &rel : rels) { - if (rel.r_offset < symbol.st_value || - symbol.st_value + symContent.size() <= rel.r_offset) + if (rel.r_offset < symValue || + symValue + symContent.size() <= rel.r_offset) continue; _references.push_back(new (_readerStorage) ELFReference( - &rel, rel.r_offset - symbol.st_value, kindArch(), + &rel, rel.r_offset - symValue, kindArch(), rel.getType(isMips64EL), rel.getSymbol(isMips64EL))); - int32_t addend = *(symContent.data() + rel.r_offset - symbol.st_value); + int32_t addend = *(symContent.data() + rel.r_offset - symValue); _references.back()->setAddend(addend); } } @@ -816,7 +824,7 @@ // _symbolToAtomMapping, so we cannot find it by calling findAtom(). We // instead call findMergeAtom(). if (symbol->getType() != llvm::ELF::STT_SECTION) - addend = symbol->st_value + addend; + addend = getSymbolValue(symbol) + addend; ELFMergeAtom *mergedAtom = findMergeAtom(shdr, addend); ref->setOffset(addend - mergedAtom->offset()); ref->setAddend(0); @@ -890,9 +898,10 @@ uint64_t ELFFile::symbolContentSize(const Elf_Shdr *section, const Elf_Sym *symbol, const Elf_Sym *nextSymbol) { + const auto symValue = getSymbolValue(symbol); // if this is the last symbol, take up the remaining data. - return nextSymbol ? nextSymbol->st_value - symbol->st_value - : section->sh_size - symbol->st_value; + return nextSymbol ? getSymbolValue(nextSymbol) - symValue + : section->sh_size - symValue; } template Index: lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -394,6 +394,7 @@ 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); + io.enumCase(value, "arm-thumb", lld::DefinedAtom::codeARMThumb); } }; Index: lld/trunk/test/elf/ARM/arm-symbols.test =================================================================== --- lld/trunk/test/elf/ARM/arm-symbols.test +++ lld/trunk/test/elf/ARM/arm-symbols.test @@ -0,0 +1,52 @@ +# Check that symbols formed from ARM instructions are valid: +# 1. Symbol address. +# 2. Symbol content size. +# 3. Symbol content. + +# RUN: yaml2obj -format=elf %s > %t-a.o +# RUN: lld -flavor gnu -target arm-linux-gnu \ +# RUN: -Bstatic --noinhibit-exec %t-a.o -o %t-a +# RUN: llvm-readobj -symbols %t-a | FileCheck -check-prefix=SYM-ADDR %s +# RUN: llvm-readobj -symbols %t-a | FileCheck -check-prefix=SYM-SIZE %s +# RUN: llvm-objdump -s -t %t-a | FileCheck -check-prefix=SYM-CONTENT %s + +# SYM-ADDR: Name: main (1) +# SYM-ADDR-NEXT: Value: 0x400074 + +# SYM-SIZE: Name: main (1) +# SYM-SIZE-NEXT: Value: 0x{{[0-9a-f]+}} +# SYM-SIZE-NEXT: Size: 28 + +# SYM-CONTENT: Contents of section .text: +# SYM-CONTENT-NEXT: 400074 04b02de5 00b08de2 0030a0e3 0300a0e1 ..-......0...... +# SYM-CONTENT-NEXT: 400084 00d04be2 04b09de4 1eff2fe1 ..K......./. + +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: 04B02DE500B08DE20030A0E30300A0E100D04BE204B09DE41EFF2FE1 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Global: + - Name: main + Type: STT_FUNC + Section: .text +... Index: lld/trunk/test/elf/ARM/defsym.test =================================================================== --- lld/trunk/test/elf/ARM/defsym.test +++ lld/trunk/test/elf/ARM/defsym.test @@ -1,28 +1,24 @@ # Check that defined symbols are present in the generated executable # RUN: yaml2obj -format=elf %s > %t-o.o -# RUN: lld -flavor gnu -target arm-linux-gnu --defsym=main=fn -e=fn \ -# RUN: -static --noinhibit-exec %t-o.o -o %t +# RUN: lld -flavor gnu -target arm-linux-gnu --defsym=main=fn \ +# RUN: -Bstatic --noinhibit-exec %t-o.o -o %t # RUN: llvm-readobj -symbols %t | FileCheck %s -# CHECK: Symbol { # CHECK: Name: main (1) -# CHECK: Value: 0x400075 -# CHECK: Size: 0 -# CHECK: Binding: Global (0x1) -# CHECK: Type: Function (0x2) -# CHECK: Other: 0 -# CHECK: Section: .text (0x1) -# CHECK: } -# CHECK: Symbol { +# CHECK-NEXT: Value: 0x400074 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: Function (0x2) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text (0x1) # CHECK: Name: fn (6) -# CHECK: Value: 0x400075 -# CHECK: Size: 15 -# CHECK: Binding: Global (0x1) -# CHECK: Type: Function (0x2) -# CHECK: Other: 0 -# CHECK: Section: .text (0x1) -# CHECK: } +# CHECK-NEXT: Value: 0x400074 +# CHECK-NEXT: Size: {{[0-9]+}} +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: Function (0x2) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text (0x1) --- FileHeader: @@ -36,7 +32,7 @@ Type: SHT_PROGBITS Flags: [ SHF_ALLOC, SHF_EXECINSTR ] AddressAlign: 0x0000000000000004 - Content: 80B400AF00231846BD465DF8047B7047 + Content: 04B02DE500B08DE20030A0E30300A0E100D04BE204B09DE41EFF2FE1 - Name: .data Type: SHT_PROGBITS Flags: [ SHF_WRITE, SHF_ALLOC ] @@ -47,28 +43,9 @@ Flags: [ SHF_WRITE, SHF_ALLOC ] AddressAlign: 0x0000000000000001 Content: '' - - Name: .note.GNU-stack - Type: SHT_PROGBITS - AddressAlign: 0x0000000000000001 - Content: '' Symbols: - Local: - - Name: .text - Type: STT_SECTION - Section: .text - - Name: .data - Type: STT_SECTION - Section: .data - - Name: .bss - Type: STT_SECTION - Section: .bss - - Name: .note.GNU-stack - Type: STT_SECTION - Section: .note.GNU-stack Global: - Name: fn Type: STT_FUNC Section: .text - Value: 0x0000000000000001 - Size: 0x0000000000000010 ... Index: lld/trunk/test/elf/ARM/thm-symbols.test =================================================================== --- lld/trunk/test/elf/ARM/thm-symbols.test +++ lld/trunk/test/elf/ARM/thm-symbols.test @@ -0,0 +1,52 @@ +# Check that symbols formed from Thumb instructions are valid: +# 1. Symbol address. +# 2. Symbol content size. +# 3. Symbol content. + +# RUN: yaml2obj -format=elf %s > %t-t.o +# RUN: lld -flavor gnu -target arm-linux-gnu \ +# RUN: -Bstatic --noinhibit-exec %t-t.o -o %t-t +# RUN: llvm-readobj -symbols %t-t | FileCheck -check-prefix=SYM-ADDR %s +# RUN: llvm-readobj -symbols %t-t | FileCheck -check-prefix=SYM-SIZE %s +# RUN: llvm-objdump -s -t %t-t | FileCheck -check-prefix=SYM-CONTENT %s + +# SYM-ADDR: Name: main (1) +# SYM-ADDR-NEXT: Value: 0x400075 + +# SYM-SIZE: Name: main (1) +# SYM-SIZE-NEXT: Value: 0x{{[0-9a-f]+}} +# SYM-SIZE-NEXT: Size: 16 + +# SYM-CONTENT: Contents of section .text: +# SYM-CONTENT-NEXT: 400074 80b400af 00231846 bd465df8 047b7047 .....#.F.F]..{pG + +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: 80B400AF00231846BD465DF8047B7047 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Global: + - Name: main + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 +...