LINUX.ORG.RU

переопределение функций в си

 , ,


0

2

Здравствуйте.

Пишу на Си под stm32, но это не суть. Gcc схож. Проблема в следующем.

Поскольку система встраиваемая нужно переопределить printf, чтобы он выводил данные в USART. Есть рабочий код переписанных функций, изменяющих printf под эту цель, вынесенный в отдельный файл stdio/printf.c

Вот только при линковке выдаётся следующая ругань:

compile:
    [mkdir] Created dir: C:\CoIDE\workspace\print\Debug\bin
    [mkdir] Created dir: C:\CoIDE\workspace\print\Debug\obj
       [cc] 9 total files to be compiled.
       [cc] arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -ffunction-sections -O0 -g -c -DSTM32F10X_HD -DUSE_STDPERIPH_DRIVER -D__ASSEMBLY__ -DSTM32F103ZE -IC:\CoIDE\workspace\print -IC:\CoIDE\workspace\print\stm_lib -IC:\CoIDE\workspace\print\stm_lib\inc -IC:\CoIDE\workspace\print\cmsis_boot -IC:\CoIDE\workspace\print\cmsis C:\CoIDE\workspace\print\cmsis\core_cm3.c C:\CoIDE\workspace\print\cmsis_boot\system_stm32f10x.c C:\CoIDE\workspace\print\cmsis_boot\startup\startup_stm32f10x_hd.c C:\CoIDE\workspace\print\stm_lib\src\stm32f10x_gpio.c C:\CoIDE\workspace\print\main.c C:\CoIDE\workspace\print\stdio\printf.c C:\CoIDE\workspace\print\stm_lib\src\stm32f10x_rcc.c C:\CoIDE\workspace\print\stm_lib\src\stm32f10x_usart.c C:\CoIDE\workspace\print\syscalls\syscalls.c
       [cc] Starting link
       [cc] arm-none-eabi-gcc -O0 -nostartfiles -Wl,-Map=print.map -mcpu=cortex-m3 -mthumb -LC:\CoIDE\workspace\print -Wl,--gc-sections -Wl,-TC:\CoIDE\workspace\print\link.ld -g -o print.elf ..\obj\core_cm3.o ..\obj\system_stm32f10x.o ..\obj\startup_stm32f10x_hd.o ..\obj\stm32f10x_gpio.o ..\obj\main.o ..\obj\printf.o ..\obj\stm32f10x_rcc.o ..\obj\stm32f10x_usart.o ..\obj\syscalls.o
       [cc] c:/coide/arm-2011.03-coocox/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/lib/thumb2\libc.a(lib_a-impure.o):(.data+0x0): multiple definition of `_impure_ptr'
       [cc] collect2: ld returned 1 exit status
       [cc] ..\obj\printf.o:(.data+0xf0): first defined here

BUILD FAILED
Total time: 3 seconds

Встаёт вопрос - как адекватно подменить системный printf на свой?

Если нужно дополнительно запостить комманды компилятора/линкера - напишите.

Заранее спасибо.



Последнее исправление: CYB3R (всего исправлений: 1)

Надо думать, вы просто форкнули код libc и чего-то там наменяли, но имена глобальных переменных оставили как есть. Значит нужно либо

1. поменять имена всех глобальных переменных в вашей форкнутой версии так, чтобы они не пересекались с оригинальным iibc

2. юзать свою версию libc при сборке проекта, с уже наложенными патчами

3. удалить все новые определения глоьальных переменных/функций из вашего форка так, чтобы они подцеплялись из стандартного libc.

как-то так... мне кажется наиболее няшным второй метод

mashina ★★★★★
()
Ответ на: комментарий от mashina

а ещё лучше как-нибудь сделать внешнее перенаправление stdout в ваш usart, без костылей в libc.

mashina ★★★★★
()

1. А в линуксе так же?
2. Новую функцию назвать __printf и сделать

#define printf __printf

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от mashina

хм. всем спасибо большое за подсказки. мысли были схожие. всплыла новая подробность. оказывается gnu arm toolchain использует newlib вместо libc, в которой одна из «фишечек» т.н. «multilibs»:

Newlib, by default, builds «multilibs». What this term means is that multiple versions of newlib are built according to a set of permutated options determined by the compiler. For example, for a chip that can be set to either run in big-endian or little-endian mode, the compiler would designate target libraries be built with each endianness. In the case where there are multiple features, the compiler will designate libraries be built with permutations of the various options so as to cover all possible combinations.

Буду разбираться как этим добром пользоваться. Ну или действительно проще переопределить поток вывода.

billy_bob
() автор топика
Ответ на: комментарий от billy_bob

А дефолтный принтф куда печатает? Я думаю, стандартный поток ввода-вывода изначально не определён, его надо, в общих чертах, задать в виде двух переменных, которые являются указателями на функции putchar() и getchar(), их уже сам пишешь и указываешь на них. Так у меня, по крайней мере, с avr-libc было.

prischeyadro ★★★☆☆
()
Ответ на: комментарий от prischeyadro

дефолтный printf через кучу вызовов в итоге вызывает заглушку, которую надо переопределить. Они просто пустые. Для разных производителей туда нужно засунуть разный код (что странно - ядро то вроде одно, ну да ладно). Поставщик IDE и доп. библиотек CooCox этот код предлагает и говорит, мол «просто включите опцию retarget у линкера, подмените код в файле printf.c и всё заработает». Просто, да не просто. Где то напортачили. На схожий баг на форуме отписались в духе «переустановите среду и всё заработает».

Другой вариант - китайцы, поставщики железа работают через подмену потоков, но в голом виде это не работает, пока не разбирался почему.

В общем всё не просто.

billy_bob
() автор топика

int my_printf(...) {}
#define printf my_printfb

andreyu ★★★★★
()
Ответ на: комментарий от billy_bob

Для разных производителей туда нужно засунуть разный код (что странно - ядро то вроде одно, ну да ладно).

Всё правильно, арм - это только ядро, а уарт - это периферия, её каждый производитель самостоятельно клепает.

Ты, по-моему, в правильном направлении смотришь, разберись один раз и потом используй, чем костыли гоородить.

prischeyadro ★★★☆☆
()
#ifndef STDOUT_USART
#define STDOUT_USART <номер порта uart>
#endif
nand
()

Не надо только забывать что gcc может сконвертить printf в puts

#include <stdio.h>

#define HIHI "Don't try to use printf - it is useless\n"
#define HIPU "Don't try to use puts - it is useless\n"

__wrap_puts(char *format)
{
        write(1, HIPU, sizeof(HIPU));
}

__wrap_printf(char *format, ...)
{
        write(1, HIHI, sizeof(HIHI));
}

main()
{
        printf("Hello world\n");
        return 0;
}
$ gcc -o wrapper wrapper.c -Wl,--wrap,printf,--wrap,puts
$ ./wrapper 
Don't try to use puts - it is useless
io ★★
()

а если просто переопределить stdout? как-то так

(victor@desktop)~ $> cat tst.c                                                                          [sh]
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main ()
{
  int fd;
    
  fd = open ("output.log", O_WRONLY | O_CREAT | O_APPEND, 0644);
  dup2 (fd, 1);

  printf ("stdout line\n");
  fprintf (stderr, "stderr line\n");
  
  close (fd);
  
  return 0;
}
(victor@desktop)~ $> gcc -o tst tst.c                                                                   [sh]
(victor@desktop)~ $> ./tst                                                                              [sh]
stderr line
(victor@desktop)~ $> cat output.log                                                                     [sh]
stdout line
(victor@desktop)~ $>                                                                                    [sh]
ananas ★★★★★
()
Ответ на: комментарий от billy_bob

CooCox

кокос под вайн ставил, или под виндой работаешь?

что-то у меня с вайном не получилось.

yura--m
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.