diff --git a/include/eld/Diagnostics/DiagRelocations.inc b/include/eld/Diagnostics/DiagRelocations.inc index 57296edee..765b324ae 100644 --- a/include/eld/Diagnostics/DiagRelocations.inc +++ b/include/eld/Diagnostics/DiagRelocations.inc @@ -30,7 +30,7 @@ DIAG(unknown_reloc_section_type, DiagnosticEngine::Unreachable, "unknown relocation section type: `%0' in section `%1'") DIAG(unsupport_cond_branch_reloc, DiagnosticEngine::Error, "applying relocation `%0', conditional branch to PLT in THUMB-2 not " - "supported yet") + "supported yet for symbol `%1' referred from %2[%3]") DIAG(copyrelocs_is_error, DiagnosticEngine::Error, "Cannot copy symbol %0 referenced in %1 from dynamic library %1 due to -z " "nocopyrelocs ") diff --git a/include/eld/Driver/GnuLinkerOptions.td b/include/eld/Driver/GnuLinkerOptions.td index 6f08f0db0..d5f1b9396 100644 --- a/include/eld/Driver/GnuLinkerOptions.td +++ b/include/eld/Driver/GnuLinkerOptions.td @@ -225,6 +225,16 @@ defm Ttext_segment "Specify an address for the .text-segment segment">, MetaVarName<"
">, Group; +defm Trodata_segment + : dashEqWithOpt<"Trodata-segment", "Trodata-segment", "Trodata_segment", + "Specify an address for the first byte of the read-only data segment">, + MetaVarName<"
">, + Group; +defm Tldata_segment + : dashEqWithOpt<"Tldata-segment", "Tldata-segment", "Tldata_segment", + "Specify an address for the first byte of the ldata segment">, + MetaVarName<"
">, + Group; defm Tdata : smDash<"Tdata", "Tdata", "Specify an address for the .data section">, MetaVarName<"
">, diff --git a/lib/Target/ARM/ARMRelocator.cpp b/lib/Target/ARM/ARMRelocator.cpp index ecf3df0aa..76ec2cb40 100644 --- a/lib/Target/ARM/ARMRelocator.cpp +++ b/lib/Target/ARM/ARMRelocator.cpp @@ -667,6 +667,27 @@ void ARMRelocator::scanGlobalReloc(InputFile &pInput, Relocation::Type Type, case llvm::ELF::R_ARM_THM_JUMP11: case llvm::ELF::R_ARM_THM_JUMP8: { std::lock_guard relocGuard(m_RelocMutex); + + // Check if this symbol already has a PLT, or is about to be granted one + bool needsPLT = false; + if (rsym->reserved() & ReservePLT) { + needsPLT = true; + } else if ((rsym->type() == ResolveInfo::IndirectFunc) && config().isCodeStatic()) { + needsPLT = true; + } else if (getTarget().isSymbolPreemptible(*rsym) && rsym->visibility() != ResolveInfo::Hidden) { + needsPLT = true; + } + + // If a PLT is involved and this is a JUMP19, throw our detailed error immediately! + if (needsPLT && pReloc.type() == llvm::ELF::R_ARM_THM_JUMP19) { + config().raise(Diag::unsupport_cond_branch_reloc) + << (int)pReloc.type() + << rsym->name() + << pReloc.getSourcePath(config().options()) + << pSection.name(); + return; + } + // These are branch relocation (except PREL31) // A PLT entry is needed when building shared library @@ -1100,12 +1121,6 @@ Relocator::Result thm_jump19(Relocation &pReloc, ARMRelocator &pParent) { helper_clear_thumb_bit(S); } - if (0x0 == T) { - // FIXME: conditional branch to PLT in THUMB-2 not supported yet - DiagEngine->raise(Diag::unsupport_cond_branch_reloc) << (int)pReloc.type(); - return Relocator::BadReloc; - } - Relocator::DWord X = ((S + A) | T) - P; int32_t SignedValue = static_cast(X); if (!llvm::isInt<21>(SignedValue)) diff --git a/lib/Target/ARM/THMToARMStub.cpp b/lib/Target/ARM/THMToARMStub.cpp index ef30e863d..e291dfa2c 100644 --- a/lib/Target/ARM/THMToARMStub.cpp +++ b/lib/Target/ARM/THMToARMStub.cpp @@ -89,7 +89,8 @@ bool THMToARMStub::isNeeded(const Relocation *pReloc, int64_t pTargetValue, !(pReloc->symInfo()->reserved() & Relocator::ReservePLT)) return false; // always need a stub to switch mode for JUMp24 - if (pReloc->type() == llvm::ELF::R_ARM_THM_JUMP24) { + if (pReloc->type() == llvm::ELF::R_ARM_THM_JUMP24 || + pReloc->type() == llvm::ELF::R_ARM_THM_JUMP19) { return true; } // Other relocation needs stub only if it cannot reach @@ -104,11 +105,13 @@ bool THMToARMStub::isRelocInRange(const class Relocation *pReloc, Offset = pTargetValue + addend - pReloc->place(Module); switch (pReloc->type()) { case llvm::ELF::R_ARM_THM_JUMP24: - case llvm::ELF::R_ARM_THM_CALL: { + case llvm::ELF::R_ARM_THM_CALL:{ if (m_Target->isJ1J2BranchEncoding()) return llvm::isInt(Offset); return llvm::isInt(Offset); } + case llvm::ELF::R_ARM_THM_JUMP19: + return llvm::isInt<21>(Offset); default: break; } diff --git a/lib/Target/ARM/THMToTHMStub.cpp b/lib/Target/ARM/THMToTHMStub.cpp index 7013368b8..1fb10f0c1 100644 --- a/lib/Target/ARM/THMToTHMStub.cpp +++ b/lib/Target/ARM/THMToTHMStub.cpp @@ -92,7 +92,9 @@ bool THMToTHMStub::isNeeded(const Relocation *pReloc, int64_t pTargetValue, Module &Module) const { int64_t Offset = 0; // This stub cannot be used for ARM target. - if ((pTargetValue & 0x1) == 0) + if ((pTargetValue & 0x1) == 0 && + pReloc->type() != llvm::ELF::R_ARM_THM_JUMP19 && + pReloc->type() != llvm::ELF::R_ARM_THM_JUMP24) return false; // The stub is needed only if the target is unreachable return !isRelocInRange(pReloc, pTargetValue, Offset, Module); @@ -107,11 +109,13 @@ bool THMToTHMStub::isRelocInRange(const Relocation *pReloc, Offset = pTargetValue + addend - pReloc->place(Module); switch (pReloc->type()) { case llvm::ELF::R_ARM_THM_JUMP24: - case llvm::ELF::R_ARM_THM_CALL: { + case llvm::ELF::R_ARM_THM_CALL:{ if (m_Target->isJ1J2BranchEncoding()) return llvm::isInt(Offset); return llvm::isInt(Offset); } + case llvm::ELF::R_ARM_THM_JUMP19: + return llvm::isInt<21>(Offset); default: break; } diff --git a/test/ARM/standalone/THMJump19Veneer/thm-jump19-basic.s b/test/ARM/standalone/THMJump19Veneer/thm-jump19-basic.s new file mode 100644 index 000000000..ee462f2ca --- /dev/null +++ b/test/ARM/standalone/THMJump19Veneer/thm-jump19-basic.s @@ -0,0 +1,30 @@ +// Tests that R_ARM_THM_JUMP19 (conditional branch) links successfully +// for an in-range target without requiring a stub. +// Regression test for https://github.com/qualcomm/eld/issues/1005 + +// RUN: %clang %clangopts %s -o %t.o -c --target=arm-none-eabi -mcpu=cortex-m33 -mfloat-abi=soft +// RUN: %link %linkopts %t.o -o %t.out --entry=my_func -static +// RUN: %objdump -d %t.out | %filecheck %s + +// CHECK: : +// CHECK: {{.*}} beq.w {{.*}} + +// CHECK: : +// CHECK-NEXT: {{.*}} bx lr + + .syntax unified + .thumb + + .section .text.caller, "ax", %progbits + .thumb_func + .global my_func + .type my_func, %function +my_func: + cmp r0, #0 + beq plain_entry + bx lr + + .section .text.target, "ax", %progbits + .global plain_entry +plain_entry: + bx lr \ No newline at end of file diff --git a/test/ARM/standalone/THMJump19Veneer/thm-jump19-plt-diag.s b/test/ARM/standalone/THMJump19Veneer/thm-jump19-plt-diag.s new file mode 100644 index 000000000..357a5b3b8 --- /dev/null +++ b/test/ARM/standalone/THMJump19Veneer/thm-jump19-plt-diag.s @@ -0,0 +1,22 @@ +// Tests that R_ARM_THM_JUMP19 correctly emits a detailed error +// when attempting to branch to a PLT entry. +// Regression test for https://github.com/qualcomm/eld/issues/1005 + +// RUN: %clang %clangopts %s -o %t.o -c --target=arm-none-eabi -march=armv7-a +// RUN: not %link %linkopts -shared %t.o -o %t.so 2>&1 | %filecheck %s + +// CHECK: Error: +// CHECK-SAME: conditional branch to PLT in THUMB-2 not supported yet for symbol `extern_func' +// CHECK-SAME: [.text.caller][.text.caller] + + .syntax unified + .thumb + + .section .text.caller, "ax", %progbits + .thumb_func + .global my_func + .type my_func, %function +my_func: + cmp r0, #0 + beq extern_func // Conditional branch to an undefined external symbol + bx lr diff --git a/test/ARM/standalone/THMJump19Veneer/thm-jump19-veneer.s b/test/ARM/standalone/THMJump19Veneer/thm-jump19-veneer.s new file mode 100644 index 000000000..b4ff1b8db --- /dev/null +++ b/test/ARM/standalone/THMJump19Veneer/thm-jump19-veneer.s @@ -0,0 +1,41 @@ +// Tests that R_ARM_THM_JUMP19 (conditional branch) produces both T2T and T2A veneers +// when the targets are out of range (beyond 21-bit range). +// Regression test for https://github.com/qualcomm/eld/issues/1005 + +// RUN: %clang %clangopts %s -o %t.o -c --target=arm-none-eabi -march=armv7-a -mfloat-abi=soft +// RUN: echo "SECTIONS { .text.caller 0x0 : { *(.text.caller) } .text.thumb_target 0x200000 : { *(.text.thumb_target) } .text.arm_target 0x400000 : { *(.text.arm_target) } }" > %t.script +// RUN: %link %linkopts -T %t.script %t.o -o %t.out --entry=my_func -static --trace=trampolines 2>&1 | %filecheck %s + +// CHECK: Creating Stub __thumb_target_{{.*}}veneer@island-{{.*}} +// CHECK: Creating Stub __arm_target_{{.*}}veneer@island-{{.*}} + +.syntax unified + +// --- CALLER (Thumb) --- +.section .text.caller, "ax", %progbits +.thumb +.thumb_func +.global my_func +.type my_func, %function +my_func: + cmp r0, #0 + beq thumb_target // Triggers T2T Veneer + beq arm_target // Triggers T2A Veneer + bx lr + +// --- TARGET 1 (Thumb) --- +.section .text.thumb_target, "ax", %progbits +.thumb +.thumb_func +.global thumb_target +.type thumb_target, %function +thumb_target: + bx lr + +// --- TARGET 2 (ARM) --- +.section .text.arm_target, "ax", %progbits +.arm +.global arm_target +.type arm_target, %function +arm_target: + bx lr \ No newline at end of file