Index: lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp +++ lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp @@ -510,6 +510,32 @@ applyArmReloc(location, (uint32_t)result & mask, mask); } +/// \brief Fixup unresolved weak reference with NOP instruction +static bool fixupUnresolvedWeakCall(uint8_t *location, + Reference::KindValue kindValue) { + //TODO: workaround for archs without NOP instruction + switch (kindValue) { + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + // Thumb32 NOP.W + write32le(location, 0x8000F3AF); + break; + case R_ARM_THM_JUMP11: + // Thumb16 NOP + write16le(location, 0xBF00); + break; + case R_ARM_CALL: + case R_ARM_JUMP24: + // A1 NOP, save condition bits + applyArmReloc(location, 0x320F000, 0xFFFFFFF); + break; + default: + return false; + } + + return true; +} + std::error_code ARMTargetRelocationHandler::applyRelocation( ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, const Reference &ref) const { @@ -522,6 +548,19 @@ return std::error_code(); assert(ref.kindArch() == Reference::KindArch::ARM); + // Fixup unresolved weak references + if (!target) { + bool isCallFixed = fixupUnresolvedWeakCall(loc, ref.kindValue()); + + if (isCallFixed) { + DEBUG(llvm::dbgs() << "\t\tFixup unresolved weak reference '"; + llvm::dbgs() << ref.target()->name() << "'"; + llvm::dbgs() << " at address: 0x" << Twine::utohexstr(reloc); + llvm::dbgs() << (isCallFixed ? "\n" : " isn't possible\n")); + return std::error_code(); + } + } + // Calculate proper initial addend for the relocation const Reference::Addend addend = readAddend(loc, ref.kindValue()) + ref.addend(); Index: lld/trunk/test/elf/ARM/weak-branch.test =================================================================== --- lld/trunk/test/elf/ARM/weak-branch.test +++ lld/trunk/test/elf/ARM/weak-branch.test @@ -0,0 +1,222 @@ +# Check weak references fixup. + +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-jmp11.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-jmp11.o -o %t +# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=JMP11-CHECK %s + +# JMP11-CHECK: Contents of section .text: +# JMP11-CHECK: 400194 704700bf 01216be7 012100bf 002167e7 +# ^ NOP (thumb16) +# 40019c: 2101 movs r1, #1 +# 40019e: bf00 nop +# JMP11-CHECK: 4001a4 002100bf +# ^ NOP (thumb16) +# 4001a4: 2100 movs r1, #0 +# 4001a6: bf00 nop +# JMP11-CHECK: SYMBOL TABLE: +# JMP11-CHECK: 00000000 w *UND* 00000000 __gnu_h2f_internal + +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-thm-call.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-thm-call.o -o %t +# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=THM-CALL-CHECK %s + +# THM-CALL-CHECK: Contents of section .text: +# THM-CALL-CHECK: 400064 80b500af fff7f4ff aff30080 03461846 +# ^ NOP.W +# 400068: f7ff fff4 bl 400054 +# 40006c: f3af 8000 nop.w +# 400070: 4603 mov r3, r0 ; return value has not been changed after weak fn call +# +# THM-CALL-CHECK: SYMBOL TABLE: +# THM-CALL-CHECK: 00000000 w *UND* 00000000 weak_fn + +# RUN: yaml2obj -format=elf -docnum 3 %s > %t-arm-call.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-arm-call.o -o %t +# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=ARM-CALL-CHECK %s + +# ARM-CALL-CHECK: Contents of section .text: +# ARM-CALL-CHECK: 400074 04b08de2 f5ffffeb 00f020e3 0030a0e1 +# ^ NOP +# 400078: ebfffff5 bl 400054 +# 40007c: e320f000 nop {0} +# 400080: e1a03000 mov r3, r0 ; return value has not been changed after weak fn call +# +# ARM-CALL-CHECK: SYMBOL TABLE: +# ARM-CALL-CHECK: 00000000 w *UND* 00000000 weak_fn + +# jump11.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: 70B4020CC0F3C754FF2CC0F3160302F4004080B241D0002C08BF002B3BD0A4F17F0543F4000315F10E0FA8BF41F6FF7209DA15F1190FA3BFA4F166066FF07F42F2406FF07F4212EA03060CD001325208964208BF03EA42021344B3F1807F24BF5B08A4F17E0501B30F2D26DC15F1180F11DB15F10E0FB5BF4FF6F2710E35CFF6FF71AD02B7BF491BAAB2CB40002202EB5333034398B270BC70470029FBD040EA533370BC43F4FC407047102DDEDD6FEAD0336FEAC33398B2EDE740F4F84398B2E9E700BFC0F3842310B4A3F11F040029B4FA84F400F400424FEA541408BF0024C0F309002146140481B943B14203703302EBC35343EA04005DF8044B704760B1B0FA80F3153B98405B42EFE744EA40305DF8044B40F0FF40704720465DF8044B704700BF01216BE70121FEE7002167E70021FEE7 + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x000000000000012A + Symbol: __gnu_h2f_internal + Type: R_ARM_THM_JUMP11 + - Offset: 0x0000000000000132 + Symbol: __gnu_h2f_internal + Type: R_ARM_THM_JUMP11 + - 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: .text + Type: STT_SECTION + Section: .text + - Name: .data + Type: STT_SECTION + Section: .data + - Name: .bss + Type: STT_SECTION + Section: .bss + - Name: '$t' + Section: .text + - Name: __gnu_f2h_internal + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 + Size: 0x00000000000000C2 + Global: + - Name: __gnu_f2h_ieee + Type: STT_FUNC + Section: .text + Value: 0x0000000000000125 + Size: 0x0000000000000004 + Visibility: STV_HIDDEN + - Name: __gnu_h2f_ieee + Type: STT_FUNC + Section: .text + Value: 0x0000000000000129 + Size: 0x0000000000000004 + Visibility: STV_HIDDEN + - Name: __gnu_f2h_alternative + Type: STT_FUNC + Section: .text + Value: 0x000000000000012D + Size: 0x0000000000000004 + Visibility: STV_HIDDEN + - Name: __gnu_h2f_alternative + Type: STT_FUNC + Section: .text + Value: 0x0000000000000131 + Size: 0x0000000000000004 + Visibility: STV_HIDDEN + Weak: + - Name: __gnu_h2f_internal +# thm-call.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: 80B400AF01231846BD465DF8047B704780B500AFFFF7FEFFFFF7FEFF0346184680BD00BF + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000014 + Symbol: my_fn + Type: R_ARM_THM_CALL + - Offset: 0x0000000000000018 + Symbol: weak_fn + Type: R_ARM_THM_CALL +Symbols: + Local: + - Name: .text + Type: STT_SECTION + Section: .text + - Name: '$t' + Section: .text + Global: + - Name: my_fn + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 + Size: 0x0000000000000010 + - Name: main + Type: STT_FUNC + Section: .text + Value: 0x0000000000000011 + Size: 0x0000000000000012 + Weak: + - Name: weak_fn +# arm-call.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: 04B02DE500B08DE20130A0E30300A0E100D04BE204B09DE41EFF2FE100482DE904B08DE2FEFFFFEBFEFFFFEB0030A0E10300A0E10088BDE8 + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x0000000000000024 + Symbol: my_fn + Type: R_ARM_CALL + - Offset: 0x0000000000000028 + Symbol: weak_fn + Type: R_ARM_CALL +Symbols: + Local: + - Name: .text + Type: STT_SECTION + Section: .text + - Name: '$a' + Section: .text + Global: + - Name: my_fn + Type: STT_FUNC + Section: .text + Size: 0x000000000000001C + - Name: main + Type: STT_FUNC + Section: .text + Value: 0x000000000000001C + Size: 0x000000000000001C + Weak: + - Name: weak_fn +...