Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to implement syscalls with newlib nano

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
)

like image 213
W4ZM Avatar asked Oct 24 '25 03:10

W4ZM


1 Answers

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.

like image 144
W4ZM Avatar answered Oct 25 '25 18:10

W4ZM