Skip to main content
Spectramax
Associate II
January 21, 2019
Solved

Printing with GCC: printf() function never calls custom _write()

  • January 21, 2019
  • 2 replies
  • 3683 views

Hello,

I've spent quite a bit of time scratching my head and I would appreciate any guidance in this matter.

I am using Segger's Embedded Studio with Segger's RTT printf library. Everything works fine with the Segger_RTT_printf() output. I can see the output it in the terminal, no issue.

Segger also provides a SEGGER_RTT_Syscalls.c which implements the following so I can overload printf() function:

#if (defined __GNUC__) && !(defined __SES_ARM) && !(defined __CROSSWORKS_ARM)
 
#include <reent.h> // required for _write_r
#include "SEGGER_RTT.h"
 
struct _reent;
 
int _write(int file, char *ptr, int len);
int _write_r(struct _reent *r, int file, const void *ptr, size_t len);
 
int _write(int file, char *ptr, int len) {
 (void) file; /* Not used, avoid warning */
 SEGGER_RTT_Write(0, ptr, len);
 return len;
}
 
int _write_r(struct _reent *r, int file, const void *ptr, size_t len) {
 (void) file; /* Not used, avoid warning */
 (void) r; /* Not used, avoid warning */
 SEGGER_RTT_Write(0, ptr, len);
 return len;
}
 
#endif

I can compile and link OK. But, when I debug, the printf() function never calls my custom _write() function.

Instead, the debugger jumps to the following disassembly:

<iprintf>
<printf>
 B40F push {r0-r3}
 4B0A ldr r3, =0x20000080 <_impure_ptr>
 B513 push {r0-r1, r4, lr}
 681C ldr r4, [r3]
 B124 cbz r4, 0x0802E1EC
 69A3 ldr r3, [r4, #24]
 B913 cbnz r3, 0x0802E1EC
 4620 mov r0, r4
 F7FFFE00 bl 0x0802DDEC <__sinit>
 AB05 add r3, sp, #20
 9A04 ldr r2, [sp, #16]
 68A1 ldr r1, [r4, #8]
 9301 str r3, [sp, #4]
 4620 mov r0, r4
 F000FC4D bl 0x0802EA94 <_vfiprintf_r>
 B002 add sp, sp, #8
 E8BD4010 pop.w {r4, lr}
 B004 add sp, sp, #16
 4770 bx lr
 20000080 .word 0x20000080

How can I can link it properly? I am using GCC ARM compiler version 8.0.

Thank you!

    This topic has been closed for replies.
    Best answer by Spectramax

    I have managed to fix this issue by changing the linker from arm-eabi-none-g++ to arm-eabi-none-gcc.

    These options can be found in your Project Options > Code > External Build inside Segger Embedded Studio.

    In retrospect, this was pretty obvious that the linker was not linking newlib/gcc stdlib and was not able to overload _write() and _write_r() custom functions inside of SEGGER_RTT_GCC_Syscalls.c

    Hope this helps!

    2 replies

    Spectramax
    SpectramaxAuthorBest answer
    Associate II
    January 21, 2019

    I have managed to fix this issue by changing the linker from arm-eabi-none-g++ to arm-eabi-none-gcc.

    These options can be found in your Project Options > Code > External Build inside Segger Embedded Studio.

    In retrospect, this was pretty obvious that the linker was not linking newlib/gcc stdlib and was not able to overload _write() and _write_r() custom functions inside of SEGGER_RTT_GCC_Syscalls.c

    Hope this helps!

    IShar.4
    Visitor II
    August 26, 2021

    @Spectramax answer is incomplete.

    If C compiler is used then declaration below would be sufficient

    int _write(int file, char *ptr, int len) {
     (void) file; /* Not used, avoid warning */
     SEGGER_RTT_Write(0, ptr, len);
     return len;
    }

    But when it comes to C++ compiler, then all names are mangled and linker is unable to match the symbol. So in essence extern "C" declaration needs to be used. Wrap it into proper #ifdefs or other fluff.

    Minimal working version:

    extern "C" int _write(int file, char *ptr, int len) {
     (void) file; /* Not used, avoid warning */
     SEGGER_RTT_Write(0, ptr, len);
     return len;
    }