Index: include/lld/Core/DefinedAtom.h =================================================================== --- include/lld/Core/DefinedAtom.h +++ include/lld/Core/DefinedAtom.h @@ -190,11 +190,16 @@ // Attributes describe a code model used by the atom. enum CodeModel { codeNA, // no specific code model + // MIPS code models codeMipsPIC, // PIC function in a PIC / non-PIC mixed file codeMipsMicro, // microMIPS instruction encoding codeMipsMicroPIC, // microMIPS instruction encoding + PIC codeMips16, // MIPS-16 instruction encoding + // ARM code models codeARMThumb, // ARM Thumb instruction set + codeARM_a, // $a-like mapping symbol (for ARM code) + codeARM_d, // $d-like mapping symbol (for data) + codeARM_t, // $t-like mapping symbol (for Thumb code) }; struct Alignment { Index: lib/ReaderWriter/ELF/ARM/ARMELFFile.h =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMELFFile.h +++ lib/ReaderWriter/ELF/ARM/ARMELFFile.h @@ -17,6 +17,26 @@ class ARMLinkingContext; +template +class ARMELFMappingAtom : public ELFDefinedAtom { + typedef llvm::object::Elf_Sym_Impl Elf_Sym; + typedef llvm::object::Elf_Shdr_Impl Elf_Shdr; + +public: + ARMELFMappingAtom(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) {} + + DefinedAtom::CodeModel codeModel() const override { + return Model; + } +}; + template class ARMELFDefinedAtom : public ELFDefinedAtom { typedef llvm::object::Elf_Sym_Impl Elf_Sym; typedef llvm::object::Elf_Shdr_Impl Elf_Shdr; @@ -31,22 +51,21 @@ contentData, referenceStart, referenceEnd, referenceList) {} - bool isThumbFunc(const Elf_Sym *symbol) const { + bool isThumbFunc() const { + const Elf_Sym* symbol = this->_symbol; 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; + uint64_t getSymbolValue() const override { + const auto value = static_cast(this->_symbol->st_value); + return isThumbFunc() ? value & ~0x1 : value; } DefinedAtom::CodeModel codeModel() const override { - if (isThumbFunc(this->_symbol)) - return DefinedAtom::codeARMThumb; - return DefinedAtom::codeNA; + return isThumbFunc() ? DefinedAtom::codeARMThumb : DefinedAtom::codeNA; } }; @@ -79,6 +98,28 @@ ArrayRef contentData, unsigned int referenceStart, unsigned int referenceEnd, std::vector *> &referenceList) override { + if (symName.size() >= 2 && symName[0] == '$') { + switch (symName[1]) { + case 'a': + return new (this->_readerStorage) + ARMELFMappingAtom( + *this, symName, sectionName, sym, sectionHdr, contentData, + referenceStart, referenceEnd, referenceList); + case 'd': + return new (this->_readerStorage) + ARMELFMappingAtom( + *this, symName, sectionName, sym, sectionHdr, contentData, + referenceStart, referenceEnd, referenceList); + case 't': + return new (this->_readerStorage) + ARMELFMappingAtom( + *this, symName, sectionName, sym, sectionHdr, contentData, + referenceStart, referenceEnd, referenceList); + default: + // Fall through and create regular defined atom. + break; + } + } return new (this->_readerStorage) ARMELFDefinedAtom( *this, symName, sectionName, sym, sectionHdr, contentData, referenceStart, referenceEnd, referenceList); Index: lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h +++ lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h @@ -30,6 +30,13 @@ return _baseAddress; } }; + +// Special methods to check code model of atoms. +bool isARMCode(const DefinedAtom *atom); +bool isARMCode(DefinedAtom::CodeModel codeModel); +bool isThumbCode(const DefinedAtom *atom); +bool isThumbCode(DefinedAtom::CodeModel codeModel); + } // end namespace elf } // end namespace lld Index: lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp +++ lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp @@ -32,3 +32,20 @@ pm.add(std::move(pass)); ELFLinkingContext::addPasses(pm); } + +bool elf::isARMCode(const DefinedAtom *atom) { + return isARMCode(atom->codeModel()); +} + +bool elf::isARMCode(DefinedAtom::CodeModel codeModel) { + return !isThumbCode(codeModel); +} + +bool elf::isThumbCode(const DefinedAtom *atom) { + return isThumbCode(atom->codeModel()); +} + +bool elf::isThumbCode(DefinedAtom::CodeModel codeModel) { + return codeModel == DefinedAtom::codeARMThumb || + codeModel == DefinedAtom::codeARM_t; +} Index: lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp +++ lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp @@ -432,7 +432,7 @@ bool addressesThumb = false; if (const auto *definedAtom = dyn_cast(ref.target())) { - addressesThumb = (DefinedAtom::codeARMThumb == definedAtom->codeModel()); + addressesThumb = isThumbCode(definedAtom); } switch (ref.kindValue()) { Index: lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp +++ lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp @@ -155,7 +155,7 @@ // Target symbol and relocated place should have different // instruction sets in order a veneer to be generated in between. const auto *target = dyn_cast(ref.target()); - if (!target || target->codeModel() == atom.codeModel()) + if (!target || isThumbCode(target) == isThumbCode(&atom)) return std::error_code(); // TODO: For unconditional jump instructions (R_ARM_CALL and R_ARM_THM_CALL) Index: lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h +++ lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h @@ -35,9 +35,18 @@ int64_t addr) { SymbolTable::addDefinedAtom(sym, da, addr); - // Set zero bit to distinguish symbols addressing Thumb instructions + // Set zero bit to distinguish real symbols addressing Thumb instructions. + // Don't care about mapping symbols like $t and others. if (DefinedAtom::codeARMThumb == da->codeModel()) sym.st_value = static_cast(sym.st_value) | 0x1; + + // Mapping symbols should have special values of binding, type and size set. + if ((DefinedAtom::codeARM_a == da->codeModel()) || + (DefinedAtom::codeARM_d == da->codeModel()) || + (DefinedAtom::codeARM_t == da->codeModel())) { + sym.setBindingAndType(llvm::ELF::STB_LOCAL, llvm::ELF::STT_NOTYPE); + sym.st_size = 0; + } } } // elf Index: lib/ReaderWriter/ELF/Atoms.h =================================================================== --- lib/ReaderWriter/ELF/Atoms.h +++ lib/ReaderWriter/ELF/Atoms.h @@ -293,7 +293,7 @@ return Alignment(0); // Obtain proper value of st_value field. - const auto symValue = getSymbolValue(_symbol); + const auto symValue = getSymbolValue(); // Unallocated common symbols specify their alignment constraints in // st_value. @@ -429,8 +429,8 @@ 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; + virtual uint64_t getSymbolValue() const { + return _symbol->st_value; } protected: Index: lib/ReaderWriter/YAML/ReaderWriterYAML.cpp =================================================================== --- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -377,6 +377,9 @@ 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); + io.enumCase(value, "arm-a", lld::DefinedAtom::codeARM_a); + io.enumCase(value, "arm-d", lld::DefinedAtom::codeARM_d); + io.enumCase(value, "arm-t", lld::DefinedAtom::codeARM_t); } }; Index: test/elf/ARM/mapping-code-model.test =================================================================== --- /dev/null +++ test/elf/ARM/mapping-code-model.test @@ -0,0 +1,163 @@ +# Check that mapping symbols are treated as ARM or Thumb code properly. +# +# 1. ARM <=> Thumb generates both veneers. +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-a-arm.o +# RUN: yaml2obj -format=elf -docnum 3 %s > %t-t-thm.o +# RUN: lld -flavor gnu -target arm-linux-gnu --defsym=main=f_a \ +# RUN: -Bstatic --noinhibit-exec %t-a-arm.o %t-t-thm.o -o %t +# RUN: llvm-objdump -t %t | FileCheck -check-prefix=INTER %s + +# INTER: SYMBOL TABLE: +# INTER: {{[0-9a-f]+}} l F .text {{[0-9a-f]+}} __f_t_from_arm +# INTER: {{[0-9a-f]+}} l F .text {{[0-9a-f]+}} __f_a_from_thumb + +# 2. Thumb <=> Thumb doesn't generate veneers. +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-a-thm.o +# RUN: yaml2obj -format=elf -docnum 3 %s > %t-t-thm.o +# RUN: lld -flavor gnu -target arm-linux-gnu --defsym=main=f_t \ +# RUN: -Bstatic --noinhibit-exec %t-t-thm.o %t-a-thm.o -o %t +# RUN: llvm-objdump -t %t | FileCheck -check-prefix=THUMB %s + +# THUMB: SYMBOL TABLE: +# THUMB-NOT: {{[0-9a-f]+}} l F .text {{[0-9a-f]+}} __f_t_from_thumb +# THUMB-NOT: {{[0-9a-f]+}} l F .text {{[0-9a-f]+}} __f_a_from_thumb + +# f-a-arm.o +--- +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: 00482DE904B08DE2FEFFFFEBFEFFFFEA0030A0E10300A0E10088BDE8 + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000008 + Symbol: f_t + Type: R_ARM_CALL + - Offset: 0x000000000000000C + Symbol: f_t + Type: R_ARM_JUMP24 + - 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: + Local: + - Name: '$a' + Section: .text + Size: 0x0000000000000002 + - Name: '$a.f_a' + Section: .text + Value: 0x0000000000000002 + Global: + - Name: f_a + Type: STT_FUNC + Section: .text + - Name: f_t + +# f-a-thm.o +--- +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: + Local: + - Name: '$t' + Section: .text + Size: 0x0000000000000002 + - Name: '$t.f_a' + Section: .text + Value: 0x0000000000000002 + Global: + - Name: f_a + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 + +# f-t-thm.o +--- +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: 80B500AFFFF7FEFFFFF7FEBF0346184680BD00BF + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000004 + Symbol: f_a + Type: R_ARM_THM_CALL + - Offset: 0x0000000000000008 + Symbol: f_a + Type: R_ARM_THM_JUMP24 + - 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: + Local: + - Name: '$t' + Section: .text + Size: 0x0000000000000002 + - Name: '$t.f_t' + Section: .text + Value: 0x0000000000000002 + Global: + - Name: f_t + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 + - Name: f_a +... Index: test/elf/ARM/mapping-symbols.test =================================================================== --- /dev/null +++ test/elf/ARM/mapping-symbols.test @@ -0,0 +1,123 @@ +# Check that mapping symbols have zero size, local binding and none type. +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-a.o +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-t.o +# RUN: lld -flavor gnu -target arm-linux-gnu \ +# RUN: -Bstatic --noinhibit-exec %t-a.o %t-t.o -o %t +# RUN: llvm-readobj -symbols %t | FileCheck %s + +# CHECK: Name: $a (1) +# CHECK-NEXT: Value: 0x{{[0-9a-f]+}} +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local (0x0) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# +# CHECK: Name: $t (9) +# CHECK-NEXT: Value: 0x{{[0-9a-f]+}} +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local (0x0) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# +# CHECK: Name: $d (24) +# CHECK-NEXT: Value: 0x{{[0-9a-f]+}} +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local (0x0) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 + +# arm.o +--- +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: 00482DE904B08DE2FEFFFFEB0030A0E10300A0E10088BDE8 + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000008 + Symbol: _Z1fv + Type: R_ARM_CALL + - 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: + Local: + - Name: '$a' + Section: .text + Global: + - Name: main + Type: STT_FUNC + Section: .text + - Name: _Z1fv + +# thm.o +--- +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: 80B400AF40F20003C0F200031B681846BD465DF8047B7047 + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000004 + Symbol: _ZL1i + Type: R_ARM_THM_MOVW_ABS_NC + - Offset: 0x0000000000000008 + Symbol: _ZL1i + Type: R_ARM_THM_MOVT_ABS + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000004 + Content: 411C0000 +Symbols: + Local: + - Name: _ZL1i + Type: STT_OBJECT + Section: .bss + Size: 0x0000000000000004 + - Name: '$d' + Section: .bss + - Name: '$t' + Section: .text + Global: + - Name: _Z1fv + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 +...