jsiei97 / FunTechCortexMX_test

A test suite to verify that the fun tech gcc is woking.
http://fun-tech.se/stm32/
4 stars 3 forks source link

[test03] link problem: sprintf do not work #1

Open jsiei97 opened 13 years ago

jsiei97 commented 13 years ago

test03 sprintf

There is a problem using sprintf.

Basic use of sprintf like

sprintf(str, "1234") 

turns into memcpy and works.

But when using some more advanced with %d it fails during linking

sprintf(str, "%d", 4321);

We get this link error:

..linking
arm-none-eabi-gcc  -Tsrc/stm32.ld -nostartfiles -mcpu=cortex-m3 -mthumb  -mfix-cortex-m3-ldrd -o main.elf main.o startup_stm32f10x.o test03.o
/usr/local/stm32/lib/gcc/arm-none-eabi/4.4.5/../../../../arm-none-eabi/lib/thumb/libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'

More data

From

    sprintf(str, "1234");
  be:   68bb        ldr r3, [r7, #8]
  c0:   4618        mov r0, r3
  c2:   f240 0100   movw    r1, #0
  c6:   f2c0 0100   movt    r1, #0
  ca:   f04f 0205   mov.w   r2, #5
  ce:   f7ff fffe   bl  0 <memcpy>
    sprintf(str, "%d", 4321);
  fa:   68bb        ldr r3, [r7, #8]
  fc:   4618        mov r0, r3
  fe:   f240 0100   movw    r1, #0
 102:   f2c0 0100   movt    r1, #0
 106:   f241 02e1   movw    r2, #4321   ; 0x10e1
 10a:   f7ff fffe   bl  0 <sprintf>
mambrus commented 13 years ago

Hi, you need the link command file that's in the project git. You have two errors, but you see only one. First you need to implement the syscall sbrk. This call is used by malloc and is used to return the top of unallocated RAM. The reason you don't always get the error is if the compiler manages to optimize your sprintf usage without using malloc (or if malloc manages small chunks without sbrk, I don't remember which).

In newlib (under newlib/libc/system somewhere) there is an implementation that you can copy paste. I'm actually surprised you havn't got it already as there used to be a primitive angel SWI based system for arm-noname-elf.

The newlib sbrk function is only 10 or so lines of code, but you need to supply a variable that the linker (via the link command file) supplies. The variable IIRC is called _end.

I'm on Holliday and won't have access to the source for yet a week, so this is all from memory.

In TinKer there is a side project called HIXS that takes care about these problems.It's an abstract system and it works not only for ARM but for most machine-architectures. I've considered releasing it under a more permissive license than GPL but never got time for it yet.

BR Michael

Skickat från min iPad

18 apr 2011 kl. 20:28 skrev jsiei97reply@reply.github.com:

test03 sprintf

There is a problem using sprintf.

Basic use of sprintf like sprintf(str, "1234") turns into memcpy and works.

But when using some more advanced with %d it fails during linking sprintf(str, "%d", 4321);

We get this link error:

..linking
arm-none-eabi-gcc  -Tsrc/stm32.ld -nostartfiles -mcpu=cortex-m3 -mthumb  -mfix-cortex-m3-ldrd -o main.elf main.o startup_stm32f10x.o test03.o
/usr/local/stm32/lib/gcc/arm-none-eabi/4.4.5/../../../../arm-none-eabi/lib/thumb/libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'

More data

From

  • arm-none-eabi-objdump -S test03.o
   sprintf(str, "1234");
 be:    68bb          ldr    r3, [r7, #8]
 c0:    4618          mov    r0, r3
 c2:    f240 0100    movw    r1, #0
 c6:    f2c0 0100    movt    r1, #0
 ca:    f04f 0205    mov.w    r2, #5
 ce:    f7ff fffe    bl    0 
   sprintf(str, "%d", 4321);
 fa:    68bb          ldr    r3, [r7, #8]
 fc:    4618          mov    r0, r3
 fe:    f240 0100    movw    r1, #0
102:    f2c0 0100    movt    r1, #0
106:    f241 02e1    movw    r2, #4321    ; 0x10e1
10a:    f7ff fffe    bl    0 

Reply to this email directly or view it on GitHub: https://github.com/jsiei97/FunTechCortexMX_test/issues/1

jsiei97 commented 13 years ago

Well, I have only added things when I notice that I needed them. And the compiler had me fooled with sprintf since he optimized the simple case into a memcpy...

jsiei97 commented 13 years ago

You are right in newlib we have:

caddr_t
_sbrk (int incr)
{
  extern char end asm ("end"); /* Defined by the linker.  */
  static char * heap_end;
  char * prev_heap_end;

And here we have the "end" that the linker must know about:

jsiei97 commented 13 years ago

To use the sbrk from newlib we can remove the --disable-newlib-supplied-syscalls flag when we build newlib.

--- a/build_01_gcc_newlib.sh
+++ b/build_01_gcc_newlib.sh
@@ -98,7 +98,6 @@ did_it_work $?
 ../configure --target=arm-none-eabi  \
              --prefix=$TOOLPATH_STM32  \
              --enable-interwork  \
-             --disable-newlib-supplied-syscalls  \
              --with-gnu-ld  \
              --with-gnu-as  \
              --disable-shared 

And then add "end" to the linker script, just like mambrus suggests.

mambrus commented 13 years ago

That should work, yes.

Great to pinpoint the reason why sys calls for arm-none-* wasn't available. Since I've been away from Newlib since .14 I wasn't sure if they'd removed them.

Btw, I'm always building the tool-chain for elf and not eabi. The calling convention differ, and possibly also the debug format. It might be that the linker script provided by me is overzealous as a consequence. I't should work for both however. If it does, make a note of that both work for ST32 debugging with OpenOCD.

Regards /Michael

Skickat från min iPad

10 maj 2011 kl. 16:03 skrev jsiei97reply@reply.github.com:

To use the sbrk from newlib we can remove the --disable-newlib-supplied-syscalls flag when we build newlib.

--- a/build_01_gcc_newlib.sh
+++ b/build_01_gcc_newlib.sh
@@ -98,7 +98,6 @@ did_it_work $?
../configure --target=arm-none-eabi  \
             --prefix=$TOOLPATH_STM32  \
             --enable-interwork  \
-             --disable-newlib-supplied-syscalls  \
             --with-gnu-ld  \
             --with-gnu-as  \
             --disable-shared 

And then add "end" to the linker script, just like mambrus suggests.

Reply to this email directly or view it on GitHub: https://github.com/jsiei97/FunTechCortexMX_test/issues/1#comment_1131037

jsiei97 commented 13 years ago

Btw, I'm always building the tool-chain for elf and not eabi.

It seems like eabi is commonly used since project like http://www.codesourcery.com/ is using it.

The calling convention differ, and possibly also the debug format

I think you are right about the calling convention, but don't we get a elf as output in both cases?

mambrus commented 13 years ago

Skickat från min iPad

12 maj 2011 kl. 08:30 skrev jsiei97reply@reply.github.com:

Btw, I'm always building the tool-chain for elf and not eabi.

It seems like eabi is commonly used since project like http://www.codesourcery.com/ is using it.

Could be. I don't mind eabi, I'm just more used to arm-*-elf

The calling convention differ, and possibly also the debug format

I think you are right about the calling convention, but don't we get a elf as output in both cases?

It's easy to find out. Just:

xxd yourfile.xyz | less

The first 4 bytes should read:

.ELF

I think they're both elf, however there might be subtile differences that could affect the linker command-file and pre-requisite for the run-time boot.

Reply to this email directly or view it on GitHub: https://github.com/jsiei97/FunTechCortexMX_test/issues/1#comment_1144899

jsiei97 commented 12 years ago

To use the "system calls" inside newlib does not work very well, the FreeRTOS has a example on how the syscalls.c can look like.

wget https://downloads.sourceforge.net/project/freertos/FreeRTOS/V7.0.2/FreeRTOSv7.0.2.zip 
unzip FreeRTOSv7.0.2.zip 

grep -r _sbrk * | grep caddr_t
cp Demo/CORTEX_STM32F103_Primer_GCC/syscalls.c ~/stm32/FunTechCortexMX_test/src/

Then we have a old working example here:

And his new example here:

Some parts there seems to be useful.

mambrus commented 12 years ago

FreeRTOS is not following standard API. I would advice against it. Using syscalls with newlib isn't problematic because of Newlib, it's problematic because when using syscslls we begin to close-in into the platform concept. It's not Newlib that sets the boundaries but GCC. The border is however very well defined and crystal clear. One has to teach Newlib how to use syscalls however, and depending on architecture, there none or not a well functioning template.

To make it somewhat easier to get started with syscalls development under Newlib I wrote a small adaption layer called HIXS some years ago: http://kato.homelinux.org/~tinker/cgi-bin/wiki.pl/HIXS_in-depth it's basically just a struct encapsulating the functions that GCC require, but the functions are in fact function pointers and can be changed without the need of recomiling the toolchain and without any kernel dependancy. Whence the HIXS is built into the tool-chain (which includes Newlib) you have all the freedom and flexibility you need and you never need to recompile the tool-chain again for the sake of adapting syscalls.

mambrus commented 12 years ago

@#% reading both this post again and my old text, I realize I'm either dyslexic or have been in bad need of wearing those glasses I'm trying to tell myself I don't need. Read both with that in mind (and a great sense of understanding and humor).

Anyway, i'f help is needed don't hesitate to ask. This is easier that it seems, but a pain in the piip (i.e. where the sun doesn't shine) to explain in text. The HIXS struct can be found in the gnutools project. It needs some manual tweaking to get into newlib however, and you need to run autotools at least once to get a new set of scripts for ./configure

Also don't forget the Newlib mailing list, which is a great source for help and advice. Usually there's a great bunch of really helpful and competent people hanging there. Even if questions are non Newlib related, bordering to either GCC or something else, I've always found them very helpful and kind.

jsiei97 commented 12 years ago

It is working. Tag: Ver2012-02-17

Problem was in:

bjarnekvae commented 7 years ago

Hi

I'm having some problems with getting printf to work (or at least sprintf), what did you do to fix this problem? I'm using the same setup as you, arm-none-eabi-gcc with newlib, and a STM32F407 MCU.

I appreciate any help you can offer :)

mambrus commented 7 years ago

Hello bjarne89, Could you elaborate the problem. Is it for all format-strings or is it it for some specific formats like for example floats? Does ?printf work in any case, like for example no format specifiers at all? Or if it works with some format-specifiers, plese provide examples of which one(s).

Does your error furthermore manifest at compile-, link- or run-time?

Versions of at your built cross-gcc and Newlib would also be helpful.

bjarnekvae commented 7 years ago

Hei Mambrus,

The printf-function does not seem to work in any case, i only get this error during linking:

/usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/armv7e-m/fpu/libg.a(lib_a-sbrkr.o): In function _sbrk_r': /build/newlib-5zwpxE/newlib-2.2.0+git20150830.5a3d536/build/arm-none-eabi/armv7e-m/fpu/newlib/libc/reent/../../../../../../../newlib/libc/reent/sbrkr.c:58: undefined reference to _sbrk' /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/armv7e-m/fpu/libg.a(lib_a-writer.o): In function _write_r': /build/newlib-5zwpxE/newlib-2.2.0+git20150830.5a3d536/build/arm-none-eabi/armv7e-m/fpu/newlib/libc/reent/../../../../../../../newlib/libc/reent/writer.c:58: undefined reference to _write' /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/armv7e-m/fpu/libg.a(lib_a-closer.o): In function _close_r': /build/newlib-5zwpxE/newlib-2.2.0+git20150830.5a3d536/build/arm-none-eabi/armv7e-m/fpu/newlib/libc/reent/../../../../../../../newlib/libc/reent/closer.c:53: undefined reference to _close' /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/armv7e-m/fpu/libg.a(lib_a-lseekr.o): In function _lseek_r': /build/newlib-5zwpxE/newlib-2.2.0+git20150830.5a3d536/build/arm-none-eabi/armv7e-m/fpu/newlib/libc/reent/../../../../../../../newlib/libc/reent/lseekr.c:58: undefined reference to _lseek' /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/armv7e-m/fpu/libg.a(lib_a-readr.o): In function _read_r': /build/newlib-5zwpxE/newlib-2.2.0+git20150830.5a3d536/build/arm-none-eabi/armv7e-m/fpu/newlib/libc/reent/../../../../../../../newlib/libc/reent/readr.c:58: undefined reference to _read' /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/armv7e-m/fpu/libg.a(lib_a-fstatr.o): In function _fstat_r': /build/newlib-5zwpxE/newlib-2.2.0+git20150830.5a3d536/build/arm-none-eabi/armv7e-m/fpu/newlib/libc/reent/../../../../../../../newlib/libc/reent/fstatr.c:62: undefined reference to _fstat' /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/armv7e-m/fpu/libg.a(lib_a-isattyr.o): In function _isatty_r': /build/newlib-5zwpxE/newlib-2.2.0+git20150830.5a3d536/build/arm-none-eabi/armv7e-m/fpu/newlib/libc/reent/../../../../../../../newlib/libc/reent/isattyr.c:58: undefined reference to _isatty'

But the printf-function is not that important for me, but i would like to get the sprintf-function to work, this is my current setup:

` void blinkingLED_task(void pvParameters){ uint8_t string[30] = "Hello from HAL_Transmit\n"; char string2 = pvPortMalloc(50); int number = 10; sprintf(string2,"Hi, from sprintf \n");//, number);

while(1){
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_11);

    vTaskDelay(250/portTICK_PERIOD_MS);
    HAL_UART_Transmit(&huart3, &string[0], sizeof(string), 1000); //Print "Hello from HAL_Transmit

    vTaskDelay(250/portTICK_PERIOD_MS);
    HAL_UART_Transmit(&huart3, (uint8_t*)string2, 18, 1000); //Print "Hi, from sprintf"
}

} `

This compiles just fine, and the print is good too, but if I use the "sizeof"'-function in the sprintf-print (instead of the hardcoded 18), the output looks like: Hi, Hello from HAL_Transmit Hi, Hello from HAL_Transmit Hi, Hello from HAL_Transmit Hi, Hello from HAL_Transmit

The sprintf does not work with any format specifyers. I only get this error during linking: /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/armv7e-m/fpu/libg.a(lib_a-sbrkr.o): In function _sbrk_r': /build/newlib-5zwpxE/newlib-2.2.0+git20150830.5a3d536/build/arm-none-eabi/armv7e-m/fpu/newlib/libc/reent/../../../../../../../newlib/libc/reent/sbrkr.c:58: undefined reference to _sbrk'

I use: arm-none-eabi-gcc (15:4.9.3+svn231177-1) 4.9.3 20150529 (prerelease) and Newlib v2.2.0

Thanks for taking the time to help me :)

mambrus commented 7 years ago

Your Newlib version is much newer than was the case for this thread. But the case is quite similar and the reason is the same: You miss all syscalls. sbrk is just one of them, but from your link-errors provided, I.e. when trying to use printf, we can see that open, close and write are missing too. If you write a one-line test application using just malloc you will see the same link-error.

As jsei97 says, which was the case back then, make shure this flag is not used when building your toolchain:

--disable-newlib-supplied-syscalls

If you've allready checked that and the error remains, then Newlib is now producing slightly different end-results. There exists a stubbed system, which you can then try to add to your command-line when building your application called nosys. I.e. add the option -lnosys to your current x-gcc (It seems backwards but it's not. Your simply telling gcc to use a library, not to omit system-calls). , That should solve your malloc and sprintf issues. If it works, you can make this library added per default by modifying your current .spec-file which was produced by your x-chain build. There are probably several .spec-files. Which one is used default is revieled by the -v flag to gcc. (My guess is that your spec-file is tiny.spec). There is also an option for gcc to specify which .spec-file to hese, but then you might just as well use the -lnosys option directly.

Let me know if neither of these adjustments work.

bjarnekvae commented 7 years ago

OK, Ive been working on this for several hours now, and I can't seem to get the toolchain to build, I downloaded the newest toolchain from https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads, and followed the guide step-by-step, and removed the --disable-newlib-supplied-syscalls from flag from "build_toolchain.sh" (removed in two places), as you suggested. Each time I try, I get this error:

arm-none-eabi-ar rc ../libc.a *.o arm-none-eabi-ar: ../sys/lib.a: No such file or directory arm-none-eabi-ranlib libc.a rm -rf tmp rm -f crt0.o ln sys/crt0.o crt0.o >/dev/null 2>/dev/null || cp sys/crt0.o crt0.o cp: cannot stat 'sys/crt0.o': No such file or directory Makefile:1041: recipe for target 'crt0.o' failed make[8]: [crt0.o] Error 1 make[8]: Leaving directory '/home/bjarne/workspace/tools/gcc-arm-none-eabi-6_2-2016q4-20161216/build-native/newlib/arm-none-eabi/armv6-m/newlib/libc' Makefile:679: recipe for target 'all-recursive' failed make[7]: [all-recursive] Error 1 make[7]: Leaving directory '/home/bjarne/workspace/tools/gcc-arm-none-eabi-6_2-2016q4-20161216/build-native/newlib/arm-none-eabi/armv6-m/newlib/libc' Makefile:639: recipe for target 'all-recursive' failed make[6]: [all-recursive] Error 1 make[6]: Leaving directory '/home/bjarne/workspace/tools/gcc-arm-none-eabi-6_2-2016q4-20161216/build-native/newlib/arm-none-eabi/armv6-m/newlib' Makefile:450: recipe for target 'all' failed make[5]: [all] Error 2 make[5]: Leaving directory '/home/bjarne/workspace/tools/gcc-arm-none-eabi-6_2-2016q4-20161216/build-native/newlib/arm-none-eabi/armv6-m/newlib' Makefile:1229: recipe for target 'multi-do' failed make[4]: [multi-do] Error 1 make[4]: Leaving directory '/home/bjarne/workspace/tools/gcc-arm-none-eabi-6_2-2016q4-20161216/build-native/newlib/arm-none-eabi/newlib' Makefile:1145: recipe for target 'all-multi' failed make[3]: [all-multi] Error 2 make[3]: Leaving directory '/home/bjarne/workspace/tools/gcc-arm-none-eabi-6_2-2016q4-20161216/build-native/newlib/arm-none-eabi/newlib' Makefile:450: recipe for target 'all' failed make[2]: [all] Error 2 make[2]: Leaving directory '/home/bjarne/workspace/tools/gcc-arm-none-eabi-6_2-2016q4-20161216/build-native/newlib/arm-none-eabi/newlib' Makefile:8491: recipe for target 'all-target-newlib' failed make[1]: [all-target-newlib] Error 2 make[1]: Leaving directory '/home/bjarne/workspace/tools/gcc-arm-none-eabi-6_2-2016q4-20161216/build-native/newlib' Makefile:878: recipe for target 'all' failed make: *** [all] Error 2

building toolchains is pretty new for me, usually I just download a prebuilt one. Hope you can help me, and thanks in advance :)