im trying to implement syscalls for printf so i defined the functions :
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
void usart_init(void);
void usart_wait_for_flag(uint32_t mask, bool flag);
void usart_send(const uint8_t* data, uint8_t size);
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
int _isatty(int fd) {
usart_send((uint8_t*)"_isatty has been called !\r\n", 27);
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
return 1;
errno = EBADF;
return 0;
}
int _write(int fd, char* ptr, int len) {
usart_send((uint8_t*)"_write has been called !\r\n", 26);
if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
{
usart_send((uint8_t *) ptr, len);
return len;
}
errno = EBADF;
return -1;
}
int _close(int fd) {
usart_send((uint8_t*)"_close has been called !\r\n", 26);
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
return 0;
errno = EBADF;
return -1;
}
int _lseek(int fd, int ptr, int dir) {
usart_send((uint8_t*)"_lseek has been called !\r\n", 26);
(void) fd;
(void) ptr;
(void) dir;
errno = EBADF;
return -1;
}
int _read(int fd, char* ptr, int len) {
usart_send((uint8_t*)"_read has been called !\r\n", 25);
if (fd == STDIN_FILENO) return 1;
errno = EBADF;
return -1;
}
int _fstat(int fd, struct stat* st) {
usart_send((uint8_t*)"_fstat has been called !\r\n", 26);
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO) {
st->st_mode = S_IFCHR;
return 0;
}
errno = EBADF;
return 0;
}
caddr_t _sbrk(int incr){
usart_send((uint8_t*)"_sbrk has been called !\r\n", 25);
// consider as heapoverflow
errno = ENOMEM;
return (caddr_t) -1;
}
and i was trying to call printf :
#include <stdio.h>
#include <stdint.h>
#include <reent.h>
#include <sys/stat.h>
#include <errno.h>
#include "stm32f4xx.h"
void usart_init(void);
void usart_wait_for_flag(uint32_t mask, bool flag);
void usart_send(const uint8_t* data, uint8_t size);
int _isatty(int fd);
int _write(int fd, char* ptr, int len);
int _close(int fd);
int _lseek(int fd, int ptr, int dir);
int _fstat(int fd, struct stat* st);
int _read(int fd, char* ptr, int len);
caddr_t _sbrk(int incr);
void main(void){
usart_init();
int test = 12;
for (uint32_t i = 0; i < 1000000; i++);
//usart_send((uint8_t*)"disabling buffering..\r\n", 23);
// disable I/O buffering for STDOUT stream
//setvbuf(stdout, NULL, _IONBF, 0);
usart_send((uint8_t*)"calling printf..\r\n", 18);
printf("testing ... %d ...\n", test);
usart_send((uint8_t*)"entering loop..\r\n", 17);
while (1)
{
usart_send((uint8_t*)".\r", 2);
for (uint32_t i = 0; i < 2000000; i++);
}
}
but the execution stops or enters infinite loop in printf("testing ... %d ...\n", test);,
here is the .map file, and non of my implemented syscalls gets called.
and im using the following compilations flags :
target_compile_definitions(${PROJECT_NAME} PRIVATE STM32F446xx)
# Target compile options
target_compile_options(${PROJECT_NAME} PRIVATE
-mcpu=cortex-m4
-mthumb
-Wall
-ffunction-sections
-fdata-sections
-g0
)
# Target link options
target_link_options(${PROJECT_NAME} PRIVATE
-mcpu=cortex-m4
-mthumb
-T${CMAKE_CURRENT_SOURCE_DIR}/linker_script.ld
-Wl,-Map=blink.map
-Wl,--gc-sections
-static
--specs=nosys.specs
--specs=nano.specs
-nostartfiles
-Wl,--strip-all
)
After more investigation, i found the problem, in my startup.c file i copy the loaded .data section from flash to sram, but i start copying from _etext the end of the .text section, but newlib added these sections between the .text and .data sections in flash :
.rodata.str1.4 0x08001f9c 0x39
.rodata.str1.4
0x08001f9c 0x39 /usr/lib/gcc/arm-none-eabi/13.2.1/../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libg_nano.a(libc_a-nano-vfprintf.o)
0x13 (size before relaxing)
.rodata.str1.4
0x08001fd5 0x25 /usr/lib/gcc/arm-none-eabi/13.2.1/../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libg_nano.a(libc_a-nano-vfprintf_i.o)
.ARM.exidx 0x08001fd8 0x8
.ARM.exidx 0x08001fd8 0x8 /usr/lib/gcc/arm-none-eabi/13.2.1/../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libg_nano.a(libc_a-memchr.o)
.ARM.exidx 0x08001fe0 0x0 /usr/lib/gcc/arm-none-eabi/13.2.1/../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libg_nano.a(libc_a-memcpy.o)
0x8 (size before relaxing)
which made me copy this data first to the start of the sram 0x20000000 , but newlib will put an _impure_ptr at the start of .data section and it will access and dereference it when calling printf :
*(.data)
.data 0x20000000 0xc /usr/lib/gcc/arm-none-eabi/13.2.1/../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libg_nano.a(libc_a-findfp.o)
0x20000000 __sglue
.data 0x2000000c 0x50 /usr/lib/gcc/arm-none-eabi/13.2.1/../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libg_nano.a(libc_a-impure.o)
0x2000000c _impure_ptr
0x20000010 _impure_data
0x2000005c . = ALIGN (0x4)
0x2000005c _edata = .
as a result, i end up with invalid _impure_ptr that will cause hard fault.
i fixed this by adjusting my linker script to include those additional sections into .text section :
.text :
{
. = ALIGN(4);
*(.text)
*(.rodata)
*(.ARM.exidx)
*(.rodata.str1.4)
. = ALIGN(4);
_etext = .;
} >FLASH
also i want to mention that when calling printf without setvbuf(stdout, NULL, IONBF, 0);, fstat and sbrk well be called respectively . but with it only _write will be called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With