problem with crt0.o in 4.9.3 and thumb mode

Asked by hugo

Hello,

I have a question regarding crt0.o from gnu arm 4.9.3 for thumb (cortex-m3). When I finally got the software compiled and linked it would not start up. After initialising the RAM variables from ROM the startup code (from the /share directory) jumps to the label _start which I believe is in crt0.o. The second assembler instruction after _start is a jump into nirvana which leads to an exception. In my case _start ended up on address 0xb4 and the code there looked like this:

...
0x000000b4 30d8 adds r0,r0,#0xd8
0x000000b6 e59f b 0xfffffbf8
...

So I simply wrote the stack initialisation and the .bss initilisation inside the startup code and replaced the jump to _start by a jump to main. This seems to work.

My question now is: do I have to do anything else that crt0.o or crtbegin.o would have done?

Kind Regards,

Question information

Language:
English Edit question
Status:
Solved
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Solved by:
hugo
Solved:
Last query:
Last reply:
Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#1

Hi Hugo,

I am not getting the code sequence you gave when compiling with -mcpu=cortex-m3 -mthumb -specs=rdimon.specs. Can you give us a small testcase along with the command line to compile it to understand what's wrong with it?

Best regards,

Thomas

Revision history for this message
hugo (hugo-habicht) said :
#2

Hi Thomas,

thank you for your reponse.

Compile for all c files is:

/usr/arm/bin/arm-none-eabi-gcc -g -c -funsigned-bitfields -O1 -Wall -mthumb -mcpu=cortex-m3 --specs=nano.specs -Wl,--script=lpclnk.ld -c -o dp6pgm.o dp6pgm.c

Linking command line:

/usr/arm/bin/arm-none-eabi-gcc -o dp6pgm.elf lpcstt.o ....... dp6pgm.o -Wl,-Map=dp6pgm.map --specs=nano.specs -mthumb -Wl,--script=lpclnk.ld

Linker script lpclnk.ld is copied from 4.9.3 distribution with only memory addresses and sizes changed and startup code lpcstt.sx is the cortex-m3 version also from 4.9.3.

I use nano.specs now but without --specs that I got the same result. I experimented with all varieties because printf("%d") is also causing an exeption. Figured writing my own printf() is the fastest way out.

Map file excerpt:

.text 0x00000000 0xf210
 *(.isr_vector)
 .isr_vector 0x00000000 0x44 lpcstt.o
                0x00000000 __isr_vector
 *(.text*)
 .text 0x00000044 0x0 /usr/arm/bin/../lib/gcc/arm-none-eabi/4.9.3/thumb/crti.o
 .text 0x00000044 0x70 /usr/arm/bin/../lib/gcc/arm-none-eabi/4.9.3/thumb/crtbegin.o
 .text 0x000000b4 0xfc /usr/arm/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/thumb/crt0.o
                0x000000b4 _mainCRTStartup
                0x000000b4 _start
                0x0000014c __change_mode
                0x0000018c change_back
 .text 0x000001b0 0x48 lpcstt.o
                0x000001b0 Reset_Handler
                0x000001f4 DebugMon_Handler
                0x000001f4 SysTick_Handler
                0x000001f4 PendSV_Handler
                0x000001f4 SVC_Handler
                0x000001f4 DEF_IRQHandler
.......

Code in memory:

0x000000B4 30D8 ADDS r0,r0,#0xD8
0x000000B6 E59F B 0xFFFFFBF8
0x000000B8 0000 MOVS r0,r0
0x000000BA E353 B 0x00000764
0x000000BC 30CC ADDS r0,r0,#0xCC
0x000000BE 059F LSLS r7,r3,#22
0x000000C0 D003 BEQ 0x000000CA
0x000000C2 E1A0 B 0x00000406
......

Second statement is wrong already; somehow the linker inserted the wrong address.

OS is Centos 6.6 (RHEL) 64 bit processor.

Don't spend too much time on this; imho the gnu tools for arm seem to be a bit flaky; I had a lot of problems getting the code compiled and linked; does not match my experience with gnu for other processors though and really surprises me.

All I'd like to know ia what is done in the crt.... libraries.

Kind Regards,

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#3

Hi Hugo,

Your objdump confused me because the instructions are actually 32bit Thumb instructions. Here is the actual code:

00000000 <_mainCRTStartup>:
   0: e59f30d8 ldr r3, [pc, #216] ; e0 <change_back+0x8>
   4: e3530000 cmp r3, #0

Note that the encoding is the same: 30d8 e59f 0000 e353.

There is a relocation for the address e0:

000000e0 00001502 R_ARM_ABS32 00000000 __stack

So it fails for you because __stack is not defined. You should modify your linker script to define __stack and it should work just fine.

Best regards,

Thomas

Revision history for this message
hugo (hugo-habicht) said :
#4

It seems there is something not quite right with the linker. It pulls in Arm libraries again. When I call the linker directly (not through gcc) I get an error:

/usr/arm/bin/arm-none-eabi-ld: unrecognised emulation mode: float-abi=soft.
Supported emulations: armelf

Can the linker only link arm? Or thumb also? How do you specify soft float in the linker?

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#5

Hi Hugo,

This should be:

/usr/arm/bin/arm-none-eabi-gcc -g -c -funsigned-bitfields -O1 -Wall -mthumb -mcpu=cortex-m3 -mfloat-abi=soft --specs=nano.specs -Wl,--script=lpclnk.ld -c -o dp6pgm.o dp6pgm.c

for compiling and:

/usr/arm/bin/arm-none-eabi-gcc -o dp6pgm.elf lpcstt.o ....... dp6pgm.o -Wl,-Map=dp6pgm.map --specs=nano.specs -mthumb -mfloat-abi=soft -Wl,--script=lpclnk.ld

for linking.

Best regards.

Revision history for this message
hugo (hugo-habicht) said :
#6

Hi Thomas,

did the options precisely as per your post. Crashes immediately at 0xb4. That is ARM code what you have posted, the cortex-m3 is thumb only (I think at least). Is is possible that thumb crt0.o from the distribution has been compiled with -marm option?

The use of -Wl, when calling the linker through gcc is not quite obvious but your options seem to work; no arm libraries there any longer.

Kind Regards,
Hagen
.

Revision history for this message
hugo (hugo-habicht) said :
#7

Oh, and __stack is defined by the linker script; in my case it is set to 0x10008000 which I believe is the top of internal RAM of the processor.

Revision history for this message
hugo (hugo-habicht) said :
#8

Where would I find the source code for the crtxxx.o files? I could not find it in the source code tar ball. Or is that outside the gnu compiler source code?

Revision history for this message
hugo (hugo-habicht) said :
#9

Hi Thomas,

is it possible that there is a problem with the libraries? After going back to my own startup code the system starts up but then I get an exception in __floatisdf. The map file claims it came from the /thumb directory but the code does not look quite right to me:

excerpt from map file:

 .text 0x00005bcc 0x41c /usr/arm/bin/../lib/gcc/arm-none-eabi/4.9.3/thumb/libgcc.a(_arm_addsubdf3.o)
                0x00005bcc __aeabi_drsub
                0x00005bd4 __aeabi_dsub
                0x00005bd4 __subdf3
                0x00005bd8 __adddf3
                0x00005bd8 __aeabi_dadd
                0x00005ee8 __aeabi_ui2d
                0x00005ee8 __floatunsidf
                0x00005f0c __floatsidf
                0x00005f0c __aeabi_i2d
                0x00005f34 __extendsfdf2
                0x00005f34 __aeabi_f2d
                0x00005f74 __aeabi_ul2d
                0x00005f74 __floatundidf
                0x00005f88 __floatdidf
                0x00005f88 __aeabi_l2d

program code:

0x00005F0C 0000 MOVS r0,r0
0x00005F0E E330 B 0x00006572
0x00005F10 1000 ASRS r0,r0,#0
0x00005F12 03A0 LSLS r0,r4,#14
0x00005F14 FF1E012F DCD 0xFF1E012F ; ? Undefined
0x00005F18 4030 ANDS r0,r0,r6
0x00005F1A E92D4B01 PUSH {r0,r8-r9,r11,lr}
0x00005F1E E3A0 B 0x00006662
0x00005F20 4032 ANDS r2,r2,r6
0x00005F22 E284 B 0x0000642E
0x00005F24 5102 STR r2,[r0,r4]
0x00005F26 E210 B 0x0000634A
0x00005F28 0000 MOVS r0,r0
0x00005F2A 4260 RSBS r0,r4,#0
0x00005F2C 1000 ASRS r0,r0,#0
0x00005F2E E3A0 B 0x00006672
0x00005F30 FF7CEAFF DCD 0xFF7CEAFF ; ? Undefined
0x00005F34 2080 MOVS r0,#0x80
0x00005F36 E1B0 B 0x0000629A
.....

Kind regards,

Revision history for this message
hugo (hugo-habicht) said :
#10

Hi Thomas,

I disassembled the lib/gcc/arm-none-eabi/4.9.3/thumb/libgcc. The __floatsidf / __aeabi_i2d is definitely arm code. I disassembled some other libgcc in the other directories and some of them seem to be thumb code. Which one could I use?

Kind Regards,

Revision history for this message
hugo (hugo-habicht) said :
#11

Bingo!

I deleted the crt....o files and libg...a in the lib/gcc/arm-none-eabi/4.9.3 directory and replaced them with the files in the lib/gcc/arm-none-eabi/4.9.3/armv7-ar/thumb/softfp directory (Sorry, I could not find another way to convince the gnu linker to use those specific libraries). I have all nice thumb code now in the system and it works fine.

I don't want to mark that as a solution until somebody knowledgeable in the gnu linker / library system can confirm that. I'm not even sure what armv7-ar stands for but its a short term solution for me and I can get on with the job.

objdump -d works a treat and it is quite easy to identify that lib/gcc/arm-none-eabi/4.9.3/thumb/libgcc.a is not a thumb code library (see __aeabi_i2d).

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#12

Hi Hugo,

Let me reply to your post one by one.

Comment #6:

Yes you're right, this is ARM code indeed. The reason is that specifying only -mthumb but no -march or -mcpu means you are targetting old ARM processor (such as arm7tdmi). These cores support both ARM and Thumb mode and will, I believe, boot in ARM mode. Since you are targetting Cortex-M3 you should compile and link with -mcpu=cortex-m3 -mthumb and it should select arm-none-eabi/lib/armv7-m/crt0.o as explained in the "Architecture options usage" in our readme.txt file [1].

Comment #7:

Indeed, the issue is really the execution mode as you found yourself.

Comment #8:

- crt0.o comes from crt0.S in libgloss/arm directory of newlib (and can thus be found in src/newlib.tar.bz2 tarball)
- crti.o and crtn.o come from crti.S and crtn.S in libgcc/config/arm directory of gcc (and can thus be found in src/gcc.tar.bz2 tarball)
- crtbegin.o and crtend.o are, I think, generated from crtstuff.c in libgcc directory of gcc (and can thus be found in src/gcc.tar.bz2 tarball)

Comment #9:

I don't see any __floatisdf in your Map excerpt so it seems normal not to find it in libgcc.a

Comment #10:

I said before, you should make sure you compile *and* link with -mcpu=cortex-m3 (of -march=armv7-m) -mthumb and it will pick things in armv7-m directory rather than thumb.

Comment #11:

As per the multilib guide in section "Architecture options usage" of readme.txt file [1], armv7-ar is for Cortex-A and Cortex-R processors in Thumb mode. I guess it should work as this would be Thumb-2 but you'd better use what is in armv7-m. For this, just compile and link with -mcpu=cortex-m3 -mthumb.

[1] https://launchpadlibrarian.net/209775724/readme.txt

Best regards,

Thomas

Revision history for this message
hugo (hugo-habicht) said :
#13

Hi Thomas,

thank you for your reply.

#9: __floatisdf is linked on address 0x00005F0C. It is in the map file and the executable code is below.

#10: After reading your advice I did compile *and* link with -mcpu-cortex-m3 *and* -mthumb. The linker linked against lib/gcc/arm-none-eabi/4.9.3/thumb/libgcc.a which is incorrect.

#11: Thank you for your advice; I will copy those libraries instead. As I said in #10 the cpu and thumb options will include the wrong libraries.

At this point I'd actually take the opportunity to thank everybody who contributed to providing the gnu arm tool binaries.

Kind Regards,

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#14

This is strange, I cannot reproduce it. I tried the following:

arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb test.c
arm-none-eabi-gcc -o test.axf -mcpu=cortex-m3 -mthumb test.o -Wl,-Map,test.map -sepcs=rdimon.specs

With the following test.c:

int
main (void)
{
  return (int) (2. + 4.5);
}

and it takes the right libgcc. Can you reproduce the issue with this example and command lines?

Best regards.

Revision history for this message
hugo (hugo-habicht) said :
#15

Hello Thomas,

no, your example works here as well.

I actually did the options precisely as per your post #5 but I just noticed the -mcpu=cortex-3m option is missing in there. When I added the cpu option now to the linker it works with my software too.

So your post #12 under Comment #10 is really the solution.

Thank you very much for your help !

Kind Regards,

Revision history for this message
qs10086 (745763497-6) said :
#16

I want to get ELF file in thumb too. I use you command line.
Compile for all c files is:

/usr/arm/bin/arm-none-eabi-gcc -g -c -funsigned-bitfields -O1 -Wall -mthumb -mcpu=cortex-m3 --specs=nano.specs -Wl,--script=lpclnk.ld -c -o dp6pgm.o dp6pgm.c

this can work. But linking get wrong

Linking command line:

/usr/arm/bin/arm-none-eabi-gcc -o dp6pgm.elf lpcstt.o ....... dp6pgm.o -Wl,-Map=dp6pgm.map --specs=nano.specs -mthumb -Wl,--script=lpclnk.ld

Error is shown below:
/usr/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld: cannot open linker script file lpclnk.ld: No such file or directory
collect2: error: ld returned 1 exit status

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#17

Hi,

It seems lpclnk.ld is not in your current working directory, or there is a spelling mistake or the access rights are wrong.

Best regards.

Revision history for this message
qs10086 (745763497-6) said :
#18

Hi Thomas,

I still have problem.
My development board is in cortex-m3. May I use the executable ELF file to run in the system that the loader is writen by myself. Now I had got a problem that jump from .text to .plt it may trigger exception. Because the jump instruction used BLX, which can not be allowed in cortex-m3.

Can I use dynamic linking in cortex-m3?

Best regards.

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#19

No, dynamic linking seems counter to development for Cortex-M3. Usually Cortex-M3 is for running bare-metal applications, without a dynamic loader to patch the GOT entries that goes with a PLT. You should link statically.

Best regards,

Thomas