Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: newlib + malloc lock
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
podelkin
Народ, помогите все по полкам разложить.
Все началось с того, что хотел прикрутить *printf из newlib. В проекте используется FreeRTOS.
По прошлому опыту ожидал, что сразу возникнут ошибки линковки _sbrk ,_write, _read и т.д.
Но все скомпилировалось нормально cranky.gif . ToolChain от klen'а (спасибо ему)
При запуске из под отладчика выпал в _swiwrite на инструкции bkpt. Копаясь в исходниках newlib 1.19 нашел где это.
Правильно ли я понял, что это из-за сборки newlib без ключа --disable-newlib-supplied-syscalls?
Дальше я скачал yagarto, заменил компилятор. и ошибки линковки возникли (я впервые был ряд ошибкам biggrin.gif )))
Реализовал syscalls, и все заработало.
Но!!! printf использует malloc, malloc вызывает _sbrk для получения памяти. в исходниках для блокировки кучи используется
вызовы _malloc_lock и _malloc_unlock. Отладчиком смотрел, они пустые (и в исходнике newlib их смотрел)

Код
void
__malloc_lock (ptr)
     struct _reent *ptr;
{
#ifndef __SINGLE_THREAD__
  __lock_acquire_recursive (__malloc_lock_object);
#endif
}


Значит из многопоточной среды вызывать printf черевато crying.gif (и malloc тоже)
собственно вопросы:
  1. можно ли заставить ToolChain klen'a работать с моими syscalls без пересборки newlib
  2. как залочить кучу newlib в проекте FreeRTOS (пересобирать что-ли без __SINGLE_THREAD__)
  3. если прошлое нельзя, то может наоборот заставить newlib использовать vPortMalloc из FreeRTOS


За любую помощь заранее благодарен!
Сергей Борщ
QUOTE (podelkin @ Oct 24 2011, 13:37) *
заставить newlib использовать vPortMalloc из FreeRTOS
Написать в одном из исходных файлов проекта свою функцию malloc (ну и free, разумеется), которая будет вызывать vPortMalloc и прилинкуется взамен библиотечной.
podelkin
в исходниках newlib увидел MALLOC_PROVIDED, никто не пробовал объявлять? тогда вроде newlib не будет свою malloc компилить
alx2
Цитата(Сергей Борщ @ Oct 24 2011, 16:51) *
Написать в одном из исходных файлов проекта свою функцию malloc (ну и free, разумеется), которая будет вызывать vPortMalloc и прилинкуется взамен библиотечной.

malloc и free писать не надо, они уже написаны. Писать надо __malloc_lock() и __malloc_unlock(). Об этом, кстати, прямым открытым текстом написано в документации. Также скорее всего потребуется переписать _sbrk() в плане проверки исчерпания кучи. Для работы printf необходимо также реализовать системный вызов _write.
podelkin
Цитата(alx2 @ Oct 25 2011, 08:18) *
malloc и free писать не надо, они уже написаны. Писать надо __malloc_lock() и __malloc_unlock(). Об этом, кстати, прямым открытым текстом написано в документации. Также скорее всего потребуется переписать _sbrk() в плане проверки исчерпания кучи. Для работы printf необходимо также реализовать системный вызов _write.


так __malloc_lock() и __malloc_unlock() не определяются из-за ошибки линкера!

Код
multiple definition of `__malloc_lock'


нашел вот это
mail архив newlib

этож чтож - пересобирать? crying.gif
пока придумал удалить mlock.o из libc.a чтоб линкер не ругался, кто что думает

пока нашел сырое решение
опция линкера
Код
--allow-multiple-definition


теперь я могу определить свой
void __malloc_lock (struct _reent *r)
и он вызывается!
только вот криво это, буду копать дальше
podelkin
Вобщем решил сделать так:

В программе реализовал лок кучи через FreeRTOS

Код
void __malloc_lock (struct _reent *r)
{
    vPortEnterCritical();
}

void __malloc_unlock (struct _reent *r)
{
    vPortExitCritical();
}


чтоб не было ошибки линковки - выполняю команду
arm-none-eabi-ar dv libc.a lib_a-mlock.o

libc.a - который используется в данный момент ( у меня это arm-none-eabi/lib/thumb/v7m\libc.a поскольку cortex-m3), зависит от multilib

она удаляет из архива объектник с mlock.

Все. буду тестировать newlib'ский malloc, мне кажется он должен быть понадежнее, чем FreeRTOS'овский. biggrin.gif
alx2
Цитата(podelkin @ Oct 25 2011, 11:41) *
так __malloc_lock() и __malloc_unlock() не определяются из-за ошибки линкера!
Код
multiple definition of `__malloc_lock'

??? Ошибка "multiple definition", наоборот, означает, что символ __malloc_lock определен более одного раза. При этом линкер сообщает, при загрузке какого модуля эта ошибка возникла, и где (в каком модуле) этот символ был определен раньше.

Могу предположить следующее: когда Вы делали собственные версии __malloc_lock и __malloc_unlock, допустили опечатку в имени последней. В результате после загрузки модулей вашего проекта линкер не находит __malloc_unlock и загружает библиотечный mlock.o. А там __malloc_lock, который уже есть в вашем проекте!

Цитата(podelkin @ Oct 25 2011, 11:41) *
пока нашел сырое решение
опция линкера
Код
--allow-multiple-definition

ИМХО это не решение, а маскировка проблемы. Если верно сделанное мной выше предположение, то, действительно, будет вызываться ваш __malloc_lock, но вместо вашего __malloc_unlock будет вызываться "пустышка" из библиотеки...

Я бы Вам посоветовал разобраться-таки, почему линкер грузит библиотечный mlock.o, если кроме __malloc_lock и __malloc_unlock там ничего нет. Посмотрите, что там в map-файле на этот счет говорится...
alx2
Цитата(podelkin @ Oct 25 2011, 15:16) *
чтоб не было ошибки линковки - выполняю команду
arm-none-eabi-ar dv libc.a lib_a-mlock.o

Я тогда вообще не понимаю, что у Вас происходит... Если линкер загружает mlock.o из библиотеки, значит в вашем проекте присутствует неопределенный символ, имеющийся в mlock.o. Но тогда после удаления mlock.o из библиотеки линкер должен вываливаться с ошибкой "undefined reference to"... Если же символы, содержащиеся в mlock.o проекту не нужны (а так и должно быть, ибо в проекте есть собственные __malloc_lock и __malloc_unlock), какого черта линкер пытался его загружать?...

Может покажете всю команду, которой линкуется ваш проект?
podelkin
Цитата(alx2 @ Oct 26 2011, 13:02) *
Я тогда вообще не понимаю, что у Вас происходит... Если линкер загружает mlock.o из библиотеки, значит в вашем проекте присутствует неопределенный символ, имеющийся в mlock.o. Но тогда после удаления mlock.o из библиотеки линкер должен вываливаться с ошибкой "undefined reference to"... Если же символы, содержащиеся в mlock.o проекту не нужны (а так и должно быть, ибо в проекте есть собственные __malloc_lock и __malloc_unlock), какого черта линкер пытался его загружать?...

Может покажете всю команду, которой линкуется ваш проект?

Все линкуется как обычно.
На mlock ссылается сам malloc.
но в исходниках newlib __malloc_lock вызывает __lock_acquire, который определен по умолчанию как
Код
#define __lock_acquire(lock) (_CAST_VOID 0)
#define __lock_acquire_recursive(lock) (_CAST_VOID 0)

то есть символ __malloc_lock в библиотеке есть, но он ничего не делает, только мешает определить свой __malloc_lock.
Поэтому и пришлось выкинуть mlock.o из libc.a, чтоб спокойно определить свои __malloc_lock, который бы защитил кучу в много поточной среде.
После 2ух дней тестов все работает. Уже пишу, поскольку не нашел никакой информации на форуме по использованию
malloc из newlib (и *printf по зависимостям также) из многопоточной среды, надеюсь кому-то поможет.
кстати исправил определение своих символов на :
Код
void __malloc_lock(struct _reent *r)
{
    vTaskSuspendAll();
}

void __malloc_unlock(struct _reent *r)
{
    xTaskResumeAll();
}

чтоб не терять прерывания во время работы с памятью
Все работает biggrin.gif
alx2
Цитата(podelkin @ Oct 26 2011, 18:50) *
Все линкуется как обычно.
Я не знаком с обычаями линковки. sm.gif

malloc не ссылается на mlock. Он ссылается на __malloc_lock и __malloc_unlock. Но они уже определены в вашем проекте! Таким образом, эти ссылки будут удовлетворены уже при загрузке malloc.o, и никакой mlock.o из библиотеки он загружать не должен (никаких других символов кроме этих двух в mlock.o нет). Следовательно, мешать он ничему не должен, и что там написано в исходниках newlib, не должно иметь никакого значения...

Как бы то ни было, рад, что у Вас все работает.

Ну и вот для примера:
Код
kolez% cat test.c
#include <stdlib.h>
void __malloc_lock  (struct _reent *ptr) {}
void __malloc_unlock(struct _reent *ptr) {}
int main()
{
    void *mem = malloc(1000);
    free(mem);
    return 0;
}
kolez% arm-elf-gcc -Wl,-Map=test.map -o test test.c
kolez% grep mlock test.map
kolez%

Как видите, у меня mlock не прилинкован, и ничему не мешает...
podelkin
Цитата(alx2 @ Oct 26 2011, 08:12) *
Могу предположить следующее: когда Вы делали собственные версии __malloc_lock и __malloc_unlock, допустили опечатку в имени последней

Странно, может из-за кэша на работе Ваш пост от Oct 26 2011, 08:12 я увидел только сейчас.

сейчас попробовал скомпилировать простейший пример из поста выше и все собралось cranky.gif вернул lib.a к первоначалному виду и мой проект теперь компилица без ошибок
Какого лешего gcc раньше тянул mloc.o из библиотеки я так понял((
поначалу тоже подумал что я ошибся в написании __malloc_unlock, но тогда бы у меня не собралось бы приложение после выкидывания mloc.o из libc.a
(к тому же я смотрел отладчиком мои __malloc_lock и __malloc_unlock прилежно вызывались, то есть были написаны без ошибок)
Остановлюсь на том что где-то кривизна моих рук ускользнула от моего взгляда...
Вообщем alx2 респект a14.gif
А я теперь умею шаманить с символами и знаю ключ
Код
--allow-multiple-definition

который нафиг не нужен 08.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.