Index: lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp +++ lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp @@ -31,6 +31,85 @@ using namespace llvm::ELF; namespace { +// ARM B/BL instructions of static relocation veneer. +// TODO: consider different instruction set for archs below ARMv5 +// (one as for Thumb may be used though it's less optimal). +const uint8_t Veneer_ARM_B_BL_StaticAtomContent[8] = { + 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4] + 0x00, 0x00, 0x00, 0x00 // +}; + +// Thumb B/BL instructions of static relocation veneer. +// TODO: consider different instruction set for archs above ARMv5 +// (one as for ARM may be used since it's more optimal). +const uint8_t Veneer_THM_B_BL_StaticAtomContent[8] = { + 0x78, 0x47, // bx pc + 0x00, 0x00, // nop + 0xfe, 0xff, 0xff, 0xea // b +}; + +/// \brief Atoms that hold veneer code. +class VeneerAtom : public SimpleELFDefinedAtom { + StringRef _section; + +public: + VeneerAtom(const File &f, StringRef secName) + : SimpleELFDefinedAtom(f), _section(secName) {} + + Scope scope() const override { return DefinedAtom::scopeTranslationUnit; } + + SectionChoice sectionChoice() const override { + return DefinedAtom::sectionBasedOnContent; + } + + StringRef customSectionName() const override { return _section; } + + ContentType contentType() const override { + return DefinedAtom::typeCode; + } + + uint64_t size() const override { return rawContent().size(); } + + ContentPermissions permissions() const override { return permR_X; } + + Alignment alignment() const override { return Alignment(2); } + +#ifndef NDEBUG + StringRef name() const override { return _name; } + std::string _name; +#else + StringRef name() const override { return ""; } +#endif +}; + +/// \brief Atoms that hold veneer for statically relocated +/// ARM B/BL instructions. +class Veneer_ARM_B_BL_StaticAtom : public VeneerAtom { +public: + Veneer_ARM_B_BL_StaticAtom(const File &f, StringRef secName) + : VeneerAtom(f, secName) {} + + ArrayRef rawContent() const override { + return llvm::makeArrayRef(Veneer_ARM_B_BL_StaticAtomContent); + } +}; + +/// \brief Atoms that hold veneer for statically relocated +/// Thumb B/BL instructions. +class Veneer_THM_B_BL_StaticAtom : public VeneerAtom { +public: + Veneer_THM_B_BL_StaticAtom(const File &f, StringRef secName) + : VeneerAtom(f, secName) {} + + DefinedAtom::CodeModel codeModel() const override { + return DefinedAtom::codeARMThumb; + } + + ArrayRef rawContent() const override { + return llvm::makeArrayRef(Veneer_THM_B_BL_StaticAtomContent); + } +}; + class ELFPassFile : public SimpleFile { public: ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { @@ -51,12 +130,67 @@ if (ref.kindNamespace() != Reference::KindNamespace::ELF) return; assert(ref.kindArch() == Reference::KindArch::ARM); + switch (ref.kindValue()) { + case R_ARM_JUMP24: + case R_ARM_THM_JUMP24: + static_cast(this)->handleVeneer(atom, ref); + break; + } } protected: + std::error_code handleVeneer(const DefinedAtom &atom, const Reference &ref) { + // Target symbol and relocated place should have different + // instruction sets in order a veneer to be generated in between. + const auto *target = dyn_cast_or_null(ref.target()); + if (!target || target->codeModel() == atom.codeModel()) + return std::error_code(); + + // TODO: For unconditional jump instructions (R_ARM_CALL and R_ARM_THM_CALL) + // fixup isn't possible without veneer generation for archs below ARMv5. + + // Veneers may only be generated for STT_FUNC target symbols + // or for symbols located in sections different to the place of relocation. + const auto kindValue = ref.kindValue(); + StringRef secName = atom.customSectionName(); + if (DefinedAtom::typeCode != target->contentType() && + !target->customSectionName().equals(secName)) { + StringRef kindValStr; + if (!this->_ctx.registry().referenceKindToString( + ref.kindNamespace(), ref.kindArch(), kindValue, kindValStr)) { + kindValStr = "unknown"; + } + + std::string errStr = + (Twine("Reference of type ") + Twine(kindValue) + " (" + kindValStr + + ") from " + atom.name() + "+" + Twine(ref.offsetInAtom()) + " to " + + ref.target()->name() + "+" + Twine(ref.addend()) + + " cannot be effected without a veneer").str(); + + llvm_unreachable(errStr.c_str()); + } + + const Atom *veneer = nullptr; + switch (kindValue) { + case R_ARM_JUMP24: + veneer = static_cast(this) + ->getVeneer_ARM_B_BL(target, secName); + break; + case R_ARM_THM_JUMP24: + veneer = static_cast(this) + ->getVeneer_THM_B_BL(target, secName); + break; + default: + llvm_unreachable("Unhandled reference type for veneer generation"); + } + + assert(veneer && "The veneer is not set"); + const_cast(ref).setTarget(veneer); + return std::error_code(); + } + public: - ARMRelocationPass(const ELFLinkingContext &ctx) - : _file(ctx), _ctx(ctx) {} + ARMRelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {} /// \brief Do the pass. /// @@ -99,12 +233,25 @@ handleReference(*atom, *ref); } } + + // Add all created atoms to the link. + uint64_t ordinal = 0; + for (auto &veneer : _veneerVector) { + veneer->setOrdinal(ordinal++); + mf->addAtom(*veneer); + } } protected: /// \brief Owner of all the Atoms created by this pass. ELFPassFile _file; const ELFLinkingContext &_ctx; + + /// \brief Map Atoms to their veneers. + llvm::DenseMap _veneerMap; + + /// \brief the list of veneer atoms. + std::vector _veneerVector; }; /// This implements the static relocation model. Meaning GOT and PLT entries are @@ -118,6 +265,44 @@ public: ARMStaticRelocationPass(const elf::ARMLinkingContext &ctx) : ARMRelocationPass(ctx) {} + + /// \brief Get the veneer for ARM B/BL instructions. + const VeneerAtom *getVeneer_ARM_B_BL(const DefinedAtom *da, + StringRef secName) { + auto veneer = _veneerMap.find(da); + if (_veneerMap.end() != veneer) + return veneer->second; + + auto v = new (_file._alloc) Veneer_ARM_B_BL_StaticAtom(_file, secName); + v->addReferenceELF_ARM(R_ARM_ABS32, 4, da, 0); +#ifndef NDEBUG + v->_name = "__"; + v->_name += da->name(); + v->_name += "_from_arm"; +#endif + _veneerMap[da] = v; + _veneerVector.push_back(v); + return v; + } + + /// \brief Get the veneer for Thumb B/BL instructions. + const VeneerAtom *getVeneer_THM_B_BL(const DefinedAtom *da, + StringRef secName) { + auto veneer = _veneerMap.find(da); + if (_veneerMap.end() != veneer) + return veneer->second; + + auto v = new (_file._alloc) Veneer_THM_B_BL_StaticAtom(_file, secName); + v->addReferenceELF_ARM(R_ARM_JUMP24, 4, da, 0); +#ifndef NDEBUG + v->_name = "__"; + v->_name += da->name(); + v->_name += "_from_thumb"; +#endif + _veneerMap[da] = v; + _veneerVector.push_back(v); + return v; + } }; } // end of anon namespace Index: lld/trunk/test/elf/ARM/rel-arm-jump24-veneer-b.test =================================================================== --- lld/trunk/test/elf/ARM/rel-arm-jump24-veneer-b.test +++ lld/trunk/test/elf/ARM/rel-arm-jump24-veneer-b.test @@ -0,0 +1,101 @@ +# Check veneer generation for R_ARM_JUMP24 relocation (B instruction call). + +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-arm.o +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-thm.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-arm.o %t-thm.o -o %t + +# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=B-VENEER %s +# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=B-ADDR %s + +# B-VENEER: Contents of section .text: +# B-VENEER: 400074 010000ea +# Call from main: +# offset = 0x4 ^^ +# call site offset PC(arm) ___Z1fv_from_arm addr +# 0x400074 + 0x4 + 0x8 = 0x400080 +# +# Code of the veneer: +# B-VENEER: {{[0-9a-f]+}} {{[0-9a-f]+}} 04f01fe5 +# B-VENEER: 400084 79004000 +# call addr = 0x400079 ^^ +# call addr _Z1fv addr Thumb mode +# 0x400079 = 0x400078 | 0x1 +# +# B-ADDR: SYMBOL TABLE: +# B-ADDR: 00400080 l F .text {{[0-9a-f]+}} ___Z1fv_from_arm +# B-ADDR: 00400074 g F .text {{[0-9a-f]+}} main +# B-ADDR: 00400078 g F .text {{[0-9a-f]+}} _Z1fv + +# 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: FEFFFFEA + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000000 + Symbol: _Z1fv + Type: R_ARM_JUMP24 + Addend: 0 + - 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 + - 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: 4FF0000318467047 + - 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: _Z1fv + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 +... Index: lld/trunk/test/elf/ARM/rel-arm-jump24-veneer-bl.test =================================================================== --- lld/trunk/test/elf/ARM/rel-arm-jump24-veneer-bl.test +++ lld/trunk/test/elf/ARM/rel-arm-jump24-veneer-bl.test @@ -0,0 +1,100 @@ +# Check veneer generation for R_ARM_JUMP24 relocation (BL instruction call). + +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-arm.o +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-thm.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-arm.o %t-thm.o -o %t + +# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=BL-VENEER %s +# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=BL-ADDR %s + +# BL-VENEER: Contents of section .text: +# BL-VENEER: 400084 0400000b +# Call from main: +# offset = 0x10 ^^ +# call site offset PC(arm) ___Z1fv_from_arm addr +# 0x400084 + 0x10 + 0x8 = 0x40009c +# +# Code of the veneer: +# BL-VENEER: 400094 {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} 95004000 +# call addr = 0x400095 ^^ +# call addr _Z1fv addr Thumb mode +# 0x400095 = 0x400094 | 0x1 +# +# BL-ADDR: SYMBOL TABLE: +# BL-ADDR: 0040009c l F .text {{[0-9a-f]+}} ___Z1fv_from_arm +# BL-ADDR: 00400074 g F .text {{[0-9a-f]+}} main +# BL-ADDR: 00400094 g F .text {{[0-9a-f]+}} _Z1fv + +# 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: 00482DE904B08DE20030A0E3000053E3FEFFFF0B0030A0E30300A0E10088BDE8 + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000010 + Symbol: _Z1fv + Type: R_ARM_JUMP24 + Addend: 0 + - 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 + - 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: 4FF0000318467047 + - 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: _Z1fv + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 +... Index: lld/trunk/test/elf/ARM/rel-thm-jump24-veneer.test =================================================================== --- lld/trunk/test/elf/ARM/rel-thm-jump24-veneer.test +++ lld/trunk/test/elf/ARM/rel-thm-jump24-veneer.test @@ -0,0 +1,100 @@ +# Check veneer generation for R_ARM_THM_JUMP24 relocation (B instruction call). + +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-arm.o +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-thm.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-arm.o %t-thm.o -o %t + +# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=B-VENEER %s +# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=B-ADDR %s + +# B-VENEER: Contents of section .text: +# B-VENEER: 400074 {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} 00f000b8 +# Call from main: +# offset = 0x0 ^^ +# call site offset PC(thm) ___Z1fv_from_thumb addr +# 0x400080 + 0x0 + 0x4 = 0x400084 +# +# Code of the veneer: +# B-VENEER: 400084 78470000 f9ffffea +# offset = -0x1C ^^ +# call site offset PC(arm) _Z1fv +# 0x400088 + (-0x1C) + 0x8 = 0x400074 +# +# B-ADDR: SYMBOL TABLE: +# B-ADDR: 00400084 l F .text {{[0-9a-f]+}} ___Z1fv_from_thumb +# B-ADDR: 00400074 g F .text {{[0-9a-f]+}} _Z1fv +# B-ADDR: 00400080 g F .text {{[0-9a-f]+}} main + +# 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: 0030A0E30300A0E11EFF2FE1 + - 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: _Z1fv + Type: STT_FUNC + Section: .text + +# 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: FFF7FEBF + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000000 + Symbol: _Z1fv + Type: R_ARM_THM_JUMP24 + Addend: 0 + - 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 + - Name: _Z1fv +...