Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/eld/Diagnostics/DiagRelocations.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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 ")
Expand Down
10 changes: 10 additions & 0 deletions include/eld/Driver/GnuLinkerOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,16 @@ defm Ttext_segment
"Specify an address for the .text-segment segment">,
MetaVarName<"<address>">,
Group<grp_scriptopts>;
defm Trodata_segment
: dashEqWithOpt<"Trodata-segment", "Trodata-segment", "Trodata_segment",
"Specify an address for the first byte of the read-only data segment">,
MetaVarName<"<address>">,
Group<grp_scriptopts>;
defm Tldata_segment
: dashEqWithOpt<"Tldata-segment", "Tldata-segment", "Tldata_segment",
"Specify an address for the first byte of the ldata segment">,
MetaVarName<"<address>">,
Group<grp_scriptopts>;
defm Tdata
: smDash<"Tdata", "Tdata", "Specify an address for the .data section">,
MetaVarName<"<address>">,
Expand Down
27 changes: 21 additions & 6 deletions lib/Target/ARM/ARMRelocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::mutex> 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

Expand Down Expand Up @@ -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<int32_t>(X);
if (!llvm::isInt<21>(SignedValue))
Expand Down
7 changes: 5 additions & 2 deletions lib/Target/ARM/THMToARMStub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<THM2_MAX_BRANCH_BITS>(Offset);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same fix for this too.

return llvm::isInt<THM_MAX_BRANCH_BITS>(Offset);
}
case llvm::ELF::R_ARM_THM_JUMP19:
return llvm::isInt<21>(Offset);
default:
break;
}
Expand Down
8 changes: 6 additions & 2 deletions lib/Target/ARM/THMToTHMStub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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<THM2_MAX_BRANCH_BITS>(Offset);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JUMP19 is 21 bits, not 23 or 25.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix R_ARM_THM_JUMP19 to use isInt<21> instead of reusing THM2_MAX_BRANCH_BITS

return llvm::isInt<THM_MAX_BRANCH_BITS>(Offset);
}
case llvm::ELF::R_ARM_THM_JUMP19:
return llvm::isInt<21>(Offset);
default:
break;
}
Expand Down
30 changes: 30 additions & 0 deletions test/ARM/standalone/THMJump19Veneer/thm-jump19-basic.s
Original file line number Diff line number Diff line change
@@ -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: <my_func>:
// CHECK: {{.*}} beq.w {{.*}} <plain_entry>

// CHECK: <plain_entry>:
// 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
22 changes: 22 additions & 0 deletions test/ARM/standalone/THMJump19Veneer/thm-jump19-plt-diag.s
Original file line number Diff line number Diff line change
@@ -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
41 changes: 41 additions & 0 deletions test/ARM/standalone/THMJump19Veneer/thm-jump19-veneer.s
Original file line number Diff line number Diff line change
@@ -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