gcc LTO appears to strip debugging symbols - debugging

I have project, running on an ARM Cortex-M4 processor, where I'm trying to include the gcc link-time optimization (LTO) feature.
Currently my compilation and linking flags are:
CFLAGS = -ggdb -ffunction-sections -Og
LDFLAGS = -Wl,-gc-sections
Everything works fine with these flags and I'm able to correctly debug the project.
Then I tried adding -flto to CFLAGS. Although the program works fine, I'm no longer able to debug the project, with gdb complaining of missing debugging symbols. Running objdump -g on the ELF file (with LTO enabled) gives the following output:
xxx.elf: file format elf32-littlearm
Contents of the .debug_frame section:
00000000 0000000c ffffffff CIE
Version: 1
Augmentation: ""
Code alignment factor: 2
Data alignment factor: -4
Return address column: 14
DW_CFA_def_cfa: r13 ofs 0
00000010 00000018 00000000 FDE cie=00000000 pc=08002a3c..08002a88
DW_CFA_advance_loc: 2 to 08002a3e
DW_CFA_def_cfa_offset: 16
DW_CFA_offset: r4 at cfa-16
DW_CFA_offset: r5 at cfa-12
DW_CFA_offset: r6 at cfa-8
DW_CFA_offset: r14 at cfa-4
DW_CFA_nop
0000002c 0000000c ffffffff CIE
Version: 1
Augmentation: ""
Code alignment factor: 2
Data alignment factor: -4
Return address column: 14
DW_CFA_def_cfa: r13 ofs 0
0000003c 0000000c 0000002c FDE cie=0000002c pc=08002a88..08002a98
Note the missing .debug_info section. Going back to the project settings and only removing -flto from CFLAGS solves the problem. objdump -g on the ELF file without LTO now shows a .debug_info section, filled with the proper references to the functions in my project, and debugging works fine again.
How to get LTO and debug symbols to play well together?
Edit: forgot to include my gcc information. I'm using the GNU ARM Embedded Toolchain, and the test was performed on versions 5.4-2016q2 and 5.4-2016q3.

It's because gcc does not support combine -flto with -g.
You can find the details GCC Online Docs - Optimize Options
"Combining -flto with -g is currently experimental and expected to
produce unexpected results."
When you use -flto, the -g will be ignored.

The situation should have improved by now.
GCC 8 finally got the early debug info improvements:
http://hubicka.blogspot.com/2018/06/gcc-8-link-time-and-interprocedural.html
While it was possible to build with LTO and -g and debug the resulting
binary, the debug information was kind of messed up C, instead of
debug info corresponding to the language program was originally
written in. This is finally solved. [...] The main idea is to produce
DWARF early during compilation, store it into object files and during
link-time just copy necessary fragments to final object files without
need for compiler to parse it and update it.
But note that -gsplit-dwarf won't work with LTO.

One can try using attribute((used)) or alternatively one can try using the debugging symbols in a way that does not change their values.

Related

ARM cross compiler generating invalid branch argets in standard C functions

I'm working on a custom embedded project (using PlatformIO to setup the build environment), and I have found that calls to standard C functions like memset, memcpy are generating bogus code. The disassembly shows that instructions in both those functions (and others I've tried from stdlib) branch unconditionally to locations that contain no code, which of course causes the MCU (a Cortex M4, the Atmel D51) to hard-fault as it tries executing nonsense code. There are no compiler errors, only runtime errors in the form of hard-faults due to invalid instructions.
I believe it's something wrong with my compilation environment, as PlatformIO has some libraries used for an Adafruit board of the same processor, and that correctly links the functions above. Note that I am cross-compiling from Mac. Just below are the disassemblies for the memset function from the Adafruit and Custom projects:
Adafruit:
0x000012de: 02 44 add r2, r0
0x000012e0: 03 46 mov r3, r0
0x000012e2: 93 42 cmp r3, r2
0x000012e4: 00 d1 bne.n 0x12e8 <memset+10>
0x000012e6: 70 47 bx lr
0x000012e8: 03 f8 01 1b strb.w r1, [r3], #1
0x000012ec: f9 e7 b.n 0x12e2 <memset+4>
Custom:
0x000005b4: 00 30 adds r0, #0
0x000005b6: a0 e1 b.n 0x8fa <--- branch to address with no code and hard-fault
0x000005b8: 02 20 movs r0, #2
0x000005ba: 80 e0 b.n 0x6be
0x000005bc: 02 00 movs r2, r0
0x000005be: 53 e1 b.n 0x868
0x000005c0: 1e ff 2f 01 vrhadd.u16 d0, d14, d31
0x000005c4: 01 10 asrs r1, r0, #32
0x000005c6: c3 e4 b.n 0xffffff50
0x000005c8: fb ff ff ea ; <UNDEFINED> instruction: 0xfffbeaff
Even without the nonsensical branch targets, the custom version has a totally different form from the one above, suggesting to me that something horribly wrong is happening with linking. I assume the issue is at the linking stage, and not during compilation of individual object files. Linking between files that exist solely within my project causes no issue; local branching is correct. This weirdness seems confined to linking prebuilt libraries.
I should mention that the adafruit stuff also includes Arduino code, so part of that compilation process includes C++ whereas mine is purely C. I have based most of the compiler flags and build environment on the Adafruit project as it was the best reference for my own project, but I am not using arduino in any form.
Here's how the linker is called for each of the two projects
Adafruit (g++ can be interchanged with gcc w/ no error):
arm-none-eabi-g++ -o .pio/build/adafruit_grandcentral_m4/firmware.elf -T flash_without_bootloader.ld -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Os -mcpu=cortex-m4 -mthumb -Wl,--gc-sections -Wl,--check-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align --specs=nosys.specs --specs=nano.specs .pio/build/adafruit_grandcentral_m4/src/main.cpp.o -L.pio/build/adafruit_grandcentral_m4 -L/Users/work-reese/.platformio/packages/framework-arduino-samd-adafruit/variants/grand_central_m4/linker_scripts/gcc -L/Users/work-reese/.platformio/packages/framework-cmsis/CMSIS/Lib/GCC -Wl,--start-group .pio/build/adafruit_grandcentral_m4/libFrameworkArduinoVariant.a .pio/build/adafruit_grandcentral_m4/libFrameworkArduino.a -larm_cortexM4lf_math -lm -Wl,--end-group
Custom:
arm-none-eabi-ar rc .pio/build/commonsense/libFrameworkCommonSense.a .pio/build/commonsense/FrameworkCommonSense/commonsense.o .pio/build/commonsense/FrameworkCommonSense/cortex_handlers.o .pio/build/commonsense/FrameworkCommonSense/led.o .pio/build/commonsense/FrameworkCommonSense/pinConfig.o .pio/build/commonsense/FrameworkCommonSense/startup.o
arm-none-eabi-ranlib .pio/build/commonsense/libFrameworkCommonSense.a
arm-none-eabi-gcc -o .pio/build/commonsense/firmware.elf -T commonsense_linker.ld -mfpu=fpv4-sp-d16 -mthumb -Wl,--gc-sections -Wl,--check-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align --specs=nosys.specs --specs=nano.specs -mcpu=cortex-m4 .pio/build/commonsense/src/main.o -L.pio/build/commonsense -L/Users/work-reese/.platformio/packages/toolchain-gccarmnoneeabi/arm-none-eabi/lib -L/Users/work-reese/.platformio/packages/framework-cmsis/CMSIS/Lib/GCC -L/Users/work-reese/.platformio/packages/framework-commonsense/linker -Wl,--start-group .pio/build/commonsense/libFrameworkCommonSense.a -larm_cortexM4lf_math -lc_nano -lm -Wl,--end-group
This is using the arm cross compiler, version 7.2.1, and the toolchain contains distributions for libc, libc_nano, libm, etc. All the necessary libraries appear to be present.
Please note I included a few extra lines for the custom version's linking above so you can see what it's building libFrameworkCommonSense.a from. None of those files include any stdlib calls, although cortex_handlers does not have __libc_init_array in the reset handler because that was also causing hard-faults in the same way memset. The linker script is identical between the two; once again, I borrowed heavily from the adafruit project for the interrupt handlers and startup code, but I haven't seen any actual differences between the environments until now.
Adding the --print-multi-lib option shows several options that should work, namely thumb/v7e-m/fpv4-sp/softfp;#mthumb#march=armv7e-m#mfpu=fpv4-sp-d16#mfloat-abi=softfp which should be selected given the compiler flags. Weirdly, it fails to compile when printing the multilib options, citing that the object files to archive (arm-none-eabi-ar) are not present in the build directory. This is probably of no concern.
Here's the compilation for the main file, which includes the calls to memset and memcpy:
arm-none-eabi-gcc -o .pio/build/commonsense/src/main.o -c -std=gnu11 -mfpu=fpv4-sp-d16 -Og -g3 -mlong-calls --specs=nano.specs -specs=nosys.specs -fdata-sections -ffunction-sections -mfloat-abi=softfp -march=armv7e-m -mfpu=fpv4-sp-d16 -marm -mthumb-interwork -ffunction-sections -fdata-sections -Wall -mthumb -nostdlib --param max-inline-insns-single=500 -mcpu=cortex-m4 -DPLATFORMIO=50003 -D__SAMD51P20A__ -D__SAMD51__ -D__FPU_PRESENT -DARM_MATH_CM4 -DENABLE_CACHE -DVARIANT_QSPI_BAUD_DEFAULT=50000000 -DDEBUG -DADAFRUIT_LINKER -DF_CPU=120000000L -Iinclude -Isrc -I/Users/work-reese/.platformio/packages/framework-cmsis/CMSIS/Include -I/Users/work-reese/.platformio/packages/framework-cmsis-atmel/CMSIS/Device/ATMEL -I/Users/work-reese/.platformio/packages/framework-cmsis-atmel/CMSIS/Device/ATMEL/samd51 -I/Users/work-reese/.platformio/packages/framework-commonsense -I/Users/work-reese/.platformio/packages/framework-commonsense/core -I/Users/work-reese/.platformio/packages/framework-commonsense/hal -I/Users/work-reese/.platformio/packages/framework-commonsense/hal/include -I/Users/work-reese/.platformio/packages/framework-commonsense/hal/utils/include -I/Users/work-reese/.platformio/packages/framework-commonsense/hal/utils/src -I/Users/work-reese/.platformio/packages/framework-commonsense/hal/src -I/Users/work-reese/.platformio/packages/framework-commonsense/hpl -I/Users/work-reese/.platformio/packages/framework-commonsense/hri -I/Users/work-reese/.platformio/packages/framework-commonsense/sample src/main.c
Does anyone know why I would be having this behavior with incorrectly linked library functions? I've bashed on it for nearly a week, throwing many combinations of compiler flags at it to no avail. I feel there's something I'm overlooking, but don't know what. I'm glad to provide any additional information.
Side question: What is __libc_init_array(), and how necessary is it to call during program startup? I see this in the reset handler for adafruit and Atmel Studio projects. It's declared locally as a function prototype in their startup files, but reproducing the same thing in my own environment causes a hardfault as soon as the processor tries calling that function. I should think it is a part of libc or similar.
I have found that calls to standard C functions like memset, memcpy are generating bogus code. The disassembly shows that instructions in both those functions (and others I've tried from stdlib) branch unconditionally to locations that contain no code, which of course causes the MCU (a Cortex M4, the Atmel D51) to hard-fault as it tries executing nonsense code.
Actually, that is ARM code rather than thumb code. When you try to disassemble it as thumb, it's nonsense, but disassemble it as ARM it looks plausible.
Of course, your processor can't execute ARM code, but only thumb code, and in any event even a processor which could would have to encounter it in ARM mode. So no mystery on the hard fault.
What is unclear is exactly how you are ending up with ARM code in a thumb project. At first glance it appears your actual invocations of the compiler are specifying thumb, so I'd guess the problem code is actually arriving as a result of linking the wrong library.
Seems the issues are when trying to use the compiler flag -mfloat-abi=softfp. I switched over to -mfloat-abi=hard, and these linking issues seemed to go away. I confirmed that the wrong set of switches breaks the adafruit environment as well.
It still seems strange that I would have such an error based on whether I solely used hardware for floating point versus a hybrid of SW emulation and HW for FPs. None of my code was using floating point either.
Part of the reason I set to 'softfp' is that the port of FreeRTOS I found mentioned I should be using this switch. Hopefully this doesn't preclude me from using that.
My question still remains on __libc_init_array(), as that still produces a hard fault when I run it -- it's disassembly is also strange looking with branches to odd places (i.e., the exception table).

Is it true that .exe can't run without .bss section in 64bit windows?

I came across this problem when I noticed some of my old programs failed to run under modern Windows.
Here is a miniature example, built via mingw64
.text
.global start
start:
subq $0x48,%rsp
xorl %ecx,%ecx
call *__imp_ExitProcess(%rip)
addq $0x48,%rsp
ret
gcc a.s -nostdlib -nostartfiles -lkernel32 -Wl,-e,start,-s
A message box says the exe is not valid Win32 program when I open it. However the program runs successfully when I add .lcomm a,1 or
.bss
.int 0
to the source file, both effectively inserting .bss section into the exe file. Adding .data section does not solve the problem.
Is this an inherent restriction of Windows or a bug inside ld?
EDIT:
Ok. I've found many exe files without .bss or any section with uninitialized data but run well nevertheless. But this does not fully answer my question. Why my program with only .data , .text and .idata unable to run?
EDIT V2:
I think I have found the cause. The value of OptionalHeader.SizeOfImage is incorrect. Changing it to correct value solves the problem. So this is most likely a bug inside ld.

Does the GNU Toolchain for Arm Processors provide support for classic processors such as the ARM11?

Recently I have taken up an interest in learning "bare-metal" development for ARM processors using native assembly. I bought a Raspberry Pi Zero which features an ARM11 processor, and am currently looking for a toolchain to assemble and link my code. It says on this page that only the A, R and M profiles are supported by the GNU Toolchain for Arm Processors, but I have come across this source which indicates that GCC is capable of compiling code for Arm architectures all the way back to ARMv4, and indeed supports the processor that I want to compile for (ARM1176JZF-S). Is there something I'm missing here? These are conflicting sources, are they not? And if the GNU Toolchain does not in fact support the ARM11 processor, what other options do I have?
Just try it
.cpu arm7tdmi
.globl _start
_start:
bl main
b .
.globl bounce
bounce:
bx lr
int bounce ( int x );
int main ( void )
{
return(bounce(3));
}
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
arm-none-eabi-as --version
GNU assembler (GNU Binutils) 2.34
Copyright (C) 2020 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 later.
This program has absolutely no warranty.
This assembler was configured for a target of `arm-none-eabi'.
arm-none-eabi-as start.s -o start.o
arm-none-eabi-gcc -O2 -c -march=armv4t so.c -o so.o
arm-none-eabi-ld -Ttext=0x1000 start.o so.o -o so.elf
arm-none-eabi-objdump -d so.elf
Disassembly of section .text:
00001000 <main>:
1000: e92d4010 push {r4, lr}
1004: e3a00003 mov r0, #3
1008: eb000003 bl 101c <bounce>
100c: e8bd4010 pop {r4, lr}
1010: e12fff1e bx lr
00001014 <_start>:
1014: ebfffff9 bl 1000 <main>
1018: eafffffe b 1018 <_start+0x4>
0000101c <bounce>:
101c: e12fff1e bx lr
(no this is not a complete functional program, just a tools demonstration)
Remember that gnu binutils (assembler, linker and other binary utilities) and gnu gcc (c compiler) are two separate projects so there is the expectation that they are not perfectly in sync one may support things the other doesn't.
I think they dropped support for the armv2/3 which is the acorn, actual chip stuff in recent tools perhaps gcc.
arm-none-eabi-gcc -O2 -c -mcpu=arm2 so.c -o so.o
arm-none-eabi-gcc: error: unrecognized -mcpu target: arm2
arm-none-eabi-gcc: note: valid arguments are: arm8 arm810 strongarm
strongarm110 fa526 fa626 arm7tdmi arm7tdmi-s arm710t arm720t arm740t arm9 arm9tdmi arm920t arm920 arm922t arm940t ep9312 arm10tdmi arm1020t arm9e arm946e-s arm966e-s arm968e-s arm10e arm1020e arm1022e xscale iwmmxt iwmmxt2 fa606te fa626te fmp626 fa726te arm926ej-s arm1026ej-s arm1136j-s arm1136jf-s arm1176jz-s arm1176jzf-s mpcorenovfp mpcore arm1156t2-s arm1156t2f-s cortex-m1 cortex-m0 cortex-m0plus cortex-m1.small-multiply cortex-m0.small-multiply cortex-m0plus.small-multiply generic-armv7-a cortex-a5 cortex-a7 cortex-a8 cortex-a9 cortex-a12 cortex-a15 cortex-a17 cortex-r4 cortex-r4f cortex-r5 cortex-r7 cortex-r8 cortex-m7 cortex-m4 cortex-m3 marvell-pj4 cortex-a15.cortex-a7 cortex-a17.cortex-a7 cortex-a32 cortex-a35 cortex-a53 cortex-a57 cortex-a72 cortex-a73 exynos-m1 xgene1 cortex-a57.cortex-a53 cortex-a72.cortex-a53 cortex-a73.cortex-a35 cortex-a73.cortex-a53 cortex-a55 cortex-a75 cortex-a76 neoverse-n1 cortex-a75.cortex-a55 cortex-a76.cortex-a55 cortex-m23 cortex-m33 cortex-r52; did you mean ‘arm8’?
arm-none-eabi-gcc -O2 -c -march=armv2a so.c -o so.o
arm-none-eabi-gcc: error: unrecognized -march target: armv2a
arm-none-eabi-gcc: note: valid arguments are: armv4 armv4t armv5t armv5te armv5tej armv6 armv6j armv6k armv6z armv6kz armv6zk armv6t2 armv6-m armv6s-m armv7 armv7-a armv7ve armv7-r armv7-m armv7e-m armv8-a armv8.1-a armv8.2-a armv8.3-a armv8.4-a armv8.5-a armv8-m.base armv8-m.main armv8-r iwmmxt iwmmxt2; did you mean ‘armv4’?
Where older versions of gcc were fine with it.
.cpu arm2
.globl _start
_start:
bl main
b .
No warnings/errors
100c: e8bd4010 pop {r4, lr}
1010: e12fff1e bx lr
that means armv4t vs:
arm-none-eabi-gcc -O2 -c -march=armv5t so.c -o so.o
arm-none-eabi-objdump -D so.o
so.o: file format elf32-littlearm
Disassembly of section .text.startup:
00000000 <main>:
0: e3a00003 mov r0, #3
4: eafffffe b 0 <bounce>
hmm they went so far as to make it a tail optimization, okay.
int bounce ( int x );
int main ( void )
{
return(bounce(3)+2);
}
00000000 <main>:
0: e92d4010 push {r4, lr}
4: e3a00003 mov r0, #3
8: ebfffffe bl 0 <bounce>
c: e2800002 add r0, r0, #2
10: e8bd8010 pop {r4, pc}
A difference between armv4t and armv5t is you can pop pc but you cant use it for arm/thumb interwork so the compiler unless possibly told, will generate interwork compatible code.
So yes even with gcc 9.3.0 it is supported. I used the wrong computer, I thought I had the latest on this one, will edit the answer with 10.2.0
Edit
Yes, I should just rewrite this, maybe I will...
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
arm-none-eabi-as --version
GNU assembler (GNU Binutils) 2.35
Copyright (C) 2020 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 later.
This program has absolutely no warranty.
This assembler was configured for a target of `arm-none-eabi'.
.cpu arm2
.globl _start
_start:
bl main
b .
.globl bounce
bounce:
# bx lr
mov pc,lr
arm-none-eabi-as start.s -o start.o
arm-none-eabi-objdump -d start.o
start.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <_start>:
0: ebfffffe bl 0 <main>
4: eafffffe b 4 <_start+0x4>
00000008 <bounce>:
8: e1a0f00e mov pc, lr
Or try the original program
arm-none-eabi-as start.s -o start.o
arm-none-eabi-gcc -O2 -c -march=armv4t so.c -o so.o
arm-none-eabi-ld -Ttext=0x1000 start.o so.o -o so.elf
arm-none-eabi-objdump -d so.elf
so.elf: file format elf32-littlearm
Disassembly of section .text:
00001000 <main>:
1000: e92d4010 push {r4, lr}
1004: e3a00003 mov r0, #3
1008: eb000003 bl 101c <bounce>
100c: e8bd4010 pop {r4, lr}
1010: e12fff1e bx lr
00001014 <_start>:
1014: ebfffff9 bl 1000 <main>
1018: eafffffe b 1018 <_start+0x4>
0000101c <bounce>:
101c: e12fff1e bx lr
so 10.2.0 and 2.35 both support this core/cpu.
arm-none-eabi-gcc -O2 -c -march=arm2a so.c -o so.o
arm-none-eabi-gcc: error: unrecognized -march target: arm2a
arm-none-eabi-gcc: note: valid arguments are: armv4 armv4t armv5t armv5te armv5tej armv6 armv6j armv6k armv6z armv6kz armv6zk armv6t2 armv6-m armv6s-m armv7 armv7-a armv7ve armv7-r armv7-m armv7e-m armv8-a armv8.1-a armv8.2-a armv8.3-a armv8.4-a armv8.5-a armv8.6-a armv8-m.base armv8-m.main armv8-r armv8.1-m.main iwmmxt iwmmxt2
arm-none-eabi-gcc: error: missing argument to ‘-march=’
arm-none-eabi-gcc -O2 -c -mcpu=arm2 so.c -o so.o
arm-none-eabi-gcc: error: unrecognized -mcpu target: arm2
arm-none-eabi-gcc: note: valid arguments are: arm8 arm810 strongarm strongarm110 fa526 fa626 arm7tdmi arm7tdmi-s arm710t arm720t arm740t arm9 arm9tdmi arm920t arm920 arm922t arm940t ep9312 arm10tdmi arm1020t arm9e arm946e-s arm966e-s arm968e-s arm10e arm1020e arm1022e xscale iwmmxt iwmmxt2 fa606te fa626te fmp626 fa726te arm926ej-s arm1026ej-s arm1136j-s arm1136jf-s arm1176jz-s arm1176jzf-s mpcorenovfp mpcore arm1156t2-s arm1156t2f-s cortex-m1 cortex-m0 cortex-m0plus cortex-m1.small-multiply cortex-m0.small-multiply cortex-m0plus.small-multiply generic-armv7-a cortex-a5 cortex-a7 cortex-a8 cortex-a9 cortex-a12 cortex-a15 cortex-a17 cortex-r4 cortex-r4f cortex-r5 cortex-r7 cortex-r8 cortex-m7 cortex-m4 cortex-m3 marvell-pj4 cortex-a15.cortex-a7 cortex-a17.cortex-a7 cortex-a32 cortex-a35 cortex-a53 cortex-a57 cortex-a72 cortex-a73 exynos-m1 xgene1 cortex-a57.cortex-a53 cortex-a72.cortex-a53 cortex-a73.cortex-a35 cortex-a73.cortex-a53 cortex-a55 cortex-a75 cortex-a76 cortex-a76ae cortex-a77 neoverse-n1 cortex-a75.cortex-a55 cortex-a76.cortex-a55 cortex-m23 cortex-m33 cortex-m35p cortex-m55 cortex-r52; did you mean ‘arm8’?
arm-none-eabi-gcc: error: missing argument to ‘-march=’
You can see the arm1176jzf-s versions in there of which one is in the raspberry pi zero.
arm-none-eabi- vs arm-linux-gnueabi-, arm-whatever-whatever unless possibly configured in the build of the tool, will all support the same targets for the same version of gcc (or binutils).
EDIT NOTE
arm-linux-gnueabi-gcc --version
arm-linux-gnueabi-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
arm-linux-gcc -mno-thumb-interwork -O2 -c -mcpu=arm2 -march=armv2a so.c -o so.o
So this is along the lines of does gcc support armxyz. The arm2/3 was dropped recently but older versions do/did support it (there is at least one open core armv2/3 out there that is I guess license free so if you want to use it you will want some tools).
But from the above demonstration with the current tools as of this writing (10.2.0 and 2.35) the armv4/4t up to the present (armv7-a/r/m) appear supported by gcc and binutils.
So since they did purge the arm2/3 at one point which probably wasn't too hard, there is an overlap between the arm2/3 and the present armv4 to armv7 as far as the machine code goes, there are some instructions in arm2/3 that didn't make it across the acorn/advanced transition (chips to cores, different companies) some/many overlap. As with the overlap from armv4 to armv7. So technically they may wish for example to remove armv4 support at some point as it has some things as shown above that are special cased. But if you bother to dig into the sources, you will find they appear to be held together with duct tape and bailing wire, so I cant imagine there would be a strong desire to go in and rip stuff out, even if you simply searched for armv4 or armv5 or armv6 or whatever the variable name for the flag is that indicates these.
They have done it before and they might again, so be prepared, test each build of the tools when you switch to it or better yet be explicit in your build so that if/when the tool drops support it will fail to build.
What you do in that case is you use an older one. On Debian/Ubuntu/Mint, etc
sudo apt-get -y install gcc-arm-linux-gnueabi binutils-arm-linux-gnueabi
sudo apt-get -y install gcc-5-arm-linux-gnueabi
Which won't be cutting edge they will be a few major revs back. But there was a distinct change after gcc 5.x.x that makes it highly desirable to keep a hold of, gcc's optimization went downhill, binaries are larger, etc. Newer versions of Ubuntu, etc may not have the gcc-5 so you can try gcc-7 instead, you lose the gcc 5.x.x unless you can build it yourself, which eventually will become obsolete, the gnu folks don't tend to write clean C code that is meant to be compiled for many many years to come so their own tools won't build their own tools after some period of time. So if you get that deep in the hole then you run an older Linux on a virtual machine and in that Linux you grab or build the older toolchain (or windows or whatever).
While the Raspberry Pi Zero still exists I can't see armv6 support going away any time soon. It really has to do with maintainers and perhaps these conferences they have. pdp-11 support was ADDED not too many years ago and is still maintained (pdp-11s are still in use today, although with the hit to the airline industry from the virus, will see, maybe there is an opportunity to upgrade there). (pdp-11, a good first processor for learning assembly language, good simulators out there and easy to write your own).
Is the ARM11 (in the Pi Zero) still supported? Yes gcc and binutils still support it.
What do I do if/when they don't? Use an older toolchain, or worse case, run an older operating system that supports building/running the older toolchain.

Wierd GCC behaviour with ARM assembler. ANDSEQ instruction

If I try to assemble this program:
.text
main:
andseq r1,r3,r2,lsl #13
With the command gcc -c test.s, I get the following error:
Error: bad instruction `andseq r1,r3,r2,lsl#13'
After some tries I replaced andseq with andeqs, and now it compiles fine.
But if I dump the resulting obj file with objdump -d test.o I get this:
Disassembly of section .text:
00000000 <main>:
0: 00131682 andseq r1, r3, r2, lsl #13
Note how the instruction is decoded as andseq ....
Am I missing something? Is this a bug?
My system is Raspbian GNU/Linux 8, and my gcc is: gcc (Raspbian 4.9.2-10) 4.9.2. I have also tested with gcc-8.1.0 (edit, not really see edit), same results.
EDIT:
In fact, it seems Im using the same binutils with gcc8, so I really only tested this GNU assembler (GNU Binutils for Raspbian) 2.25. I'll try a more recent assembler.
For compatibility with old assembly files, GNU as defaults to divided syntax for ARM assembly. In divided syntax, andeqs is the correct mnemonic for the instruction you desire. You can issue a .syntax unified directive to select unified syntax, in which andseq is the correct mnemonic.
GNU objdump on the other hand only knows unified syntax, which explains the apparent inconsistency.
For new developments, I advise you to consistently use unified syntax if possible.
There is a good UAL vs pre-UAL mnemonic table on ARMv8 Appendix K6 "Legacy Instruction Syntax for AArch32 Instruction Sets"
One of the entries of that table is:
Pre-UAL syntax UAL equivalent
AND<c>S ANDS<c>
where eq is one of the possible condition codes <c>.

Using compile flag -ffunction-sections with debug symbols

I am compiling a C file using the gcc flag -ffunction-sections, to move every function into it's own section. The assembler is throwing the error:
job_queue.s:2395: Error: operation combines symbols in different segments
The compiler's assembly output at line 2395 is given here:
.section .debug_ranges,info
.Ldebug_ranges0:
.4byte .LBB7-.Ltext0
The symbol LBB7 is in the function (and thus the section) named ".text.add_event_handler"
The symbol Ltext0 is in the (otherwise empty) section named: ".text"
GCC --version gives:
pic30-elf-gcc.exe (GCC) 4.0.3 (dsPIC30, Microchip v3_30) (B) Build date: Jun 29 2011
If I use the compiler flag -g0 (to turn off debug info) everything compiles and runs perfectly.
My question:
Is this GCC output clearly wrong? It seems to me that GCC should have calculated the symbol LBB7's offset from the beginning of the .add_even_handler section instead of the .text section.
I suspect I am misunderstanding something because I cannot find anyone having the same difficulty on the Google.
The GCC output is definitely wrong. Perhaps it's fixed in newer GCC versions. If you can't upgrade you compiler, try compiling with -gdwarf-2 or, failing that, with -gdwarf-2 -gstrict-dwarf (for -gstrict-dwarf you'll have to upgrade the compiler too).
What this option does is to instruct GCC to generate (strict) DWARF2, which does not include non-contiguous address ranges support, introduced in DWARF3.
Of course, this may degrade the debugging information quality somewhat, YMMV.

Resources