close
Skip to content

ARM: support R_ARM_THM_JUMP19 relocation in THM stubs#1127

Open
sai18022001 wants to merge 2 commits intoqualcomm:mainfrom
sai18022001:fix/r-arm-thm-jump19-stub-support
Open

ARM: support R_ARM_THM_JUMP19 relocation in THM stubs#1127
sai18022001 wants to merge 2 commits intoqualcomm:mainfrom
sai18022001:fix/r-arm-thm-jump19-stub-support

Conversation

@sai18022001
Copy link
Copy Markdown

@sai18022001 sai18022001 commented May 4, 2026

Fixes #1005

Problem

R_ARM_THM_JUMP19 (conditional branch) failed for static ARM targets like Cortex-M0plus / Cortex-M33 with:

Error: applying relocation `51', conditional branch to PLT in THUMB-2 not supported yet

This happened because the stub factory did not recognize R_ARM_THM_JUMP19, and the relocator unconditionally rejected T=0 targets even for non-PLT symbols (plain Thumb labels without.thumb_func).

Changes

  • Added R_ARM_THM_JUMP19 to THMToTHMStub and THMToARMStub using correct 21-bit range validation (isInt<21>)
  • Implemented a PLT support check during the scanning phase (scanGlobalReloc)
  • Updated ARMRelocator.cpp to allow T=0 targets for JUMP19 when the symbol is a non-PLT Thumb label

Test

Added tests in test/ARM/standalone/THMJump19Veneer/ :

  • thm-jump19-basic.s, thm-jump19-veneer.s, thm-jump19-plt-diag.s

case llvm::ELF::R_ARM_THM_CALL:
case llvm::ELF::R_ARM_THM_JUMP19: {
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

case llvm::ELF::R_ARM_THM_CALL:
case llvm::ELF::R_ARM_THM_JUMP19: {
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.

@@ -0,0 +1,13 @@
#---THMJump19Veneer.test--------- Executable --------------------------#
Copy link
Copy Markdown
Contributor

@quic-areg quic-areg May 4, 2026

Choose a reason for hiding this comment

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

We should test the veneer case (both thm-thm and thm-arm) too. I think this test does not produce veneers since everything appears to be in range.

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.

Understood, will add test cases that force veneer creation by placing caller and target out of range, covering both THMtoTHM and THMtoARM cases.

@@ -0,0 +1,5 @@
extern int my_func(int x);
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.

The bug will reproduce without this file. You can do --entry=my_func. I think link.ld can also be dropped since this particular issue should reproduce without a linker script, but you will probably need one when testing the stub cases. Then this test could be a single .s file (test.s) with no Inputs dir.

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.

Good point, will simplify to a single .s file with --entry=my_func and drop main.c and link.ld for the basic case.

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.

After looking at existing tests in the repo, they all use an Inputs/ directory for source files. I'll follow the same convention and keep the Inputs/ dir, but will simplify to a single .s file with --entry=my_func, dropping main.c. The linker script will still be needed to force out-of-range for the veneer test cases.

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.

There are many examples of single-input assembly tests in eld, such as ARM/standalone/Relocs/arm-adr-addend.s for example.

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.

Thanks for the example. I've adopted the single .s file pattern with RUN: and CHECK: as inline comments. However, I tried using --section-start to place sections far apart (to force out-of-range for veneer creation) but it doesn't seem to be honored by ELD without a linker script , both sections end up placed sequentially regardless. So I'll need an Inputs/ dir for the linker script for the veneer test cases.

Do you have a preferred way to force out-of-range section placement without a linker script in ELD?

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.

The veneer/stub case should probably be a separate test that will most likely need a linker script.

Comment thread lib/Target/ARM/ARMRelocator.cpp Outdated
// supported yet. For non-PLT targets (plain labels in Thumb code
// without .thumb_func), proceed with the relocation.
if (pReloc.symInfo()->reserved() & Relocator::ReservePLT) {
DiagEngine->raise(Diag::unsupport_cond_branch_reloc) << (int)pReloc.type();
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.

Probably this needs to be tested at the time PLT is reserved ?

The diagnostics will need to always point to the input object file, section and symbol.

Please add a test for this.

Comment thread lib/Target/ARM/THMToTHMStub.cpp Outdated
// This stub cannot be used for ARM target.
if ((pTargetValue & 0x1) == 0)
if ((pTargetValue & 0x1) == 0 &&
pReloc->type() != llvm::ELF::R_ARM_THM_JUMP19)
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.

What if R_ARM_THM_JUMP24 ?

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.

I've updated THMToTHMStub::isNeeded to also exempt R_ARM_THM_JUMP24 alongside R_ARM_THM_JUMP19 when T=0:

if ((pTargetValue & 0x1) == 0 &&
     pReloc->type() != llvm::ELF::R_ARM_THM_JUMP19 &&
     pReloc->type() != llvm::ELF::R_ARM_THM_JUMP24)
  return false;

RUN: %clang %clangopts %p/Inputs/main.c -o %t.main.o -c --target=arm-none-eabi -mcpu=cortex-m0plus -mfloat-abi=soft
RUN: %link %linkopts %t.test.o %t.main.o -o %t.out -T %p/Inputs/link.ld -m armelf --entry=main -static 2>&1
RUN: %readelf -s %t.out | %filecheck %s
#CHECK: plain_entry
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.

Need test for veneers to make sure proper veneers are generated

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.

Still working on this with @quic-areg. I'm trying to force out-of-range section placement to trigger veneer creation, but --section-start doesn't seem to be honored by ELD without a linker script. Will add the veneer test cases once I figure out the right approach for section placement.

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.

What I had in mind is to have two tests: one testing the original case mentioned in the ticket (which you already have, and does not need a linker script) and another testing veneers, which will most likely need a linker script (I mentioned this in a separate comment).

--section-start doesn't seem to be honored by ELD without a linker script

Do you have an example? It should work without one AFAIK.

Copy link
Copy Markdown
Author

@sai18022001 sai18022001 May 5, 2026

Choose a reason for hiding this comment

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

@quic-seaswara @quic-areg
Thanks for clarifying! I tested it but the map shows .text.target placed at 0xa (sequentially after .text.caller) instead of 0x200000:

.text.caller    0x0     0xa
.text.target    0xa     0x4

Command used:

ld.eld test.o --entry=my_func -static --section-start=.text.caller=0x0 --section-start=.text.target=0x200000 Map=test.map

Am I using it incorrectly, or is there something else I should try?

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.

@quic-seaswara @quic-areg Thanks for clarifying! I tested it but the map shows .text.target placed at 0xa (sequentially after .text.caller) instead of 0x200000:

.text.caller    0x0     0xa
.text.target    0xa     0x4

Command used:

ld.eld test.o --entry=my_func -static --section-start=.text.caller=0x0 --section-start=.text.target=0x200000 Map=test.map

Am I using it incorrectly, or is there something else I should try?

Yes, you are using incorrectly, the --section-start linker command line option will work only on output sections, not input sections.

Fixes: qualcomm#1005
Signed-off-by: Sai Sanjay Chikne <saichikne180201@gmail.com>
Signed-off-by: Sai Sanjay Chikne <saichikne180201@gmail.com>
@sai18022001 sai18022001 force-pushed the fix/r-arm-thm-jump19-stub-support branch from 4573840 to 6d37e02 Compare May 7, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

R_ARM_THM_JUMP19 relocation fails for static targets

3 participants