Relocation for R_ARM_THM_ALU_PREL_11_0 is not calculated correctly

Bug #1693831 reported by Casey Smith
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Arm Embedded Toolchain
Fix Released
Undecided
Unassigned

Bug Description

I am using the gcc-arm-none-eabi version 6-2017-q1-update, which uses LD version 2.26.

I am attempting to link in some vendor libraries along with my own source code. The libraries were compiled with a different toolchain (IAR), but contain ARM ELF Relocatable object files. Using arm-none-eabi-objdump I am able to view the contents of the object files just fine.

For the must part I am able to link correctly, however I get a single link error:

relocation truncated to fit: R_ARM_THM_ALU_PREL_11_0

This relocation is used by the ADR instruction to provide an offset from the PC. Based on where the symbol ends up in relation to the relocation, the ADR may be either an ADD or SUB immediate instruction from PC. The link appears only to work correctly in the case of an ADD.

I traced the error down to the elf32_arm_final_link_relocate. Specifically this case statement:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=bfd/elf32-arm.c;h=1725c222696b846c29cefdea1fd414d88626839f;hb=HEAD#l10487

Here the addend and relocation value are calculated correctly:

  relocation -= Pa (input_section->output_section->vma
        + input_section->output_offset
        + rel->r_offset);

However then the value is assigned incorrectly:

  value = relocation;

This should be:

  value = abs(relocation);

It was originally written this way but changed for some reason. The commit that changed it was:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;f=bfd/elf32-arm.c;h=b6518b3871859f9eeb7653bf2f3baaa43fa0a5d0

I am not sure why the abs() was considered useless in this case. The commit message mentions warnings from clang.

Regardless, the assignment without the abs() call will cause the linker to think an overflow has occurred when one has not. If the resulting relocation is negative, and no abs() is performed, the following overflow check will trigger a false error for negative values:

  if (value >= 0x1000)
    return bfd_reloc_overflow;

Not only that, but the following check performed later will never evaluate to true:

  if (relocation < 0)
    insn |= 0xa00000;

Proposed solution would be to change back to:

  value = abs(relocation);

Please let me know if anymore information is needed. I can try to generate a simple example which demonstrates the problem if needed.

Thanks

Revision history for this message
Casey Smith (clegg89) wrote :
Revision history for this message
Casey Smith (clegg89) wrote :
Changed in gcc-arm-embedded:
status: New → Fix Committed
Revision history for this message
Thomas Preud'homme (thomas-preudhomme) wrote :

Great news. I suggest you also ask for a backport to binutils 2.28 so that the fix can make it to our 2017Q2 release.

Best regards.

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) wrote :

Fix is included in our 7-2017Q4 release.

Changed in gcc-arm-embedded:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.