Hi GNU ld experts!
This question is related to a StackOverflow discussion, how GNU ld handles architecture mismatches.
When the ELF objects are compiled in a different architecture than the target architecture from GNU ld.
Without passing GNU ld a target architecture, GNU ld detects the architecture in the ELF objects and
link the objects in a binary. If there are some mismatches with the object files, then GNU ld refuse the linking
with an error.
Issue #1
It isn't possible to pass the architecture to ARM GNU ld when passing the architecture via command line.
The option will not recognized and GNU ld abort with an error.
Issue #2
When trying to use a linker script and set the output architecture here, it leads in many errors
with mismatching EABI version. I have tried to find a option how to set the target EBAI version with
GNU ld, but currently didn't find the correct option, if this is possible.
On none-ARM architectures like AVR from Microchip (formerly Atmel) there are no issues with GNU ld
when setting the target architecture.
Check the section 'Secondary compatibility tag' in the ABI errata doc. Check the source code for ld.
If one tries to link armv4 and armv6-m, that fails. The ld source code for arm does explicitly deal with compatibility of differing arm architectures, perhaps guided by the ABI.
The author of the stackoverflow article writes:
Long: I just learned that ld has no issues or concerns about linking an armv4 object into an armv6-m binary despite this beeing very obvious nonsense"
But in their update, they were actually linking arm4t+armv6-m, and not armv4+armv6-m as they originally described. The test shows that armv4+armv6-m fails. And armv4t+armv6-m is considered compatible, as the ABI errata says:
At this release of the ABI (2019Q4) there are only two defined uses of Tag_also_compatible_with: To express v4T also compatible with v6-M and v6-M also compatible with v4T.
At this release of the ABI (2019Q4) there are only two defined uses of Tag_also_compatible_with:
To express v4T also compatible with v6-M and v6-M also compatible with v4T.
Thus, it seems that the linker is working as expected, and I fail to see an issue.
Did they check the behaviour of gold/mold/lld?
If this compatibility is such an obvious error, they should open a support case with Arm to have the ABI rectified. Once the ABI is corrected, the linkers will be too.
Hi!
Thanks for the quick answer.
I don't tried the same architectures as the original author on StackOverflow.
Tried this on my current projects with a Cortex-M7 (Armv7E-M).
I compiled the source code with the following GCC options:
CCFLAGS += -march=armv7e-m CCFLAGS += -mcpu=cortex-m7
Without selecting the target architecture with GNU ld, GNU ld detects the correct architecture.
But when I use a linker script with selecting the output target architecture...
OUTPUT_ARCH(armv7e-m) OUTPUT_FORMAT(elf32-littlearm)
...the linking fails with EABI version mismatches...
arm-none-eabi-ld: error: source object main.o has EABI version 5, but target main_cm7.elf has EABI version 0 arm-none-eabi-ld: failed to merge target specific data of file main.o
I used the following GNU toolchain version binaries from the ARM site:
$ arm-none-eabi-ld --version GNU ld (GNU Arm Embedded Toolchain 10.3-2021.07) 2.36.1.20210621 Copyright (C) 2021 Free Software Foundation, Inc. This program is free software; you may redistribute it under the terms of the GNU General Public License version 3 or (at your option) a later version. This program has absolutely no warranty.
Currently don't tried a newer version.
I will try gold/mold/lld, if there is the same issue and also look into the GNU ld sources.
Thanks for the links, I will check them too.
EDIT:
I invoke GNU ld directly in the Makefile, not via GCC.
Can also post the full Makefile and the full linker script, which I currently use for my projects.
Thank you for the details. I understand the issue now.
The ld linker does scan for the OUTPUT_ARCH(armv7e-m) in its list of archs/processors and does find a match for armv7e-m. But when the arch is non-default, the linker fails to correctly set the output format. At this line, if a check: if(in_flags == 0) {elf_flags_init (obfd) = false; return true;} is added, the link can be made to succeed.
if(in_flags == 0) {elf_flags_init (obfd) = false; return true;}
For the non-default (i.e. failing) argument, it marks the output flags as initialized even if the input flags are 0 i.e. not initialized. For the default (i.e. success) case, it does not mark the output flag as initialized if the input flags are 0. The above one-liner check resets the output flag marks the output flag as uninitialized if it finds that the input flags are 0. The link succeeds but I do not know enough to say if this is a problem, or not.
Note that OUTPUT_ARCH(arm) still works - it correctly sets armv7e-m in the final output binary. If other linkers succeed with force-setting a non-default OUTPUT_ARCH, then this could indicate a problem with ld. I haven't checked ld.gold, or mold, or lld yet.
Confirmed that ld.gold works with OUTPUT_ARCH(armv7e-m). This indicates a bug with GNU ld.
Thank you for the detailed explanation and confirmation!
Should I report this issue back to ARM or to the GNU bug tracker, if this issue isn't known yet?
the GNU bug tracker.
Done.
Here is the link to the bug report.