Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Что делает Си-код до main?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
imiron13
Немного почитал про это здесь:
http://infocenter.arm.com/help/index.jsp?t...i/Bce3gfea.html
(использую RVDS4)

Не совсем понятно с настройкой стека. Там пишут, что настройку стека выполняет пользовательский стартап код.
Я так и делаю, но еще до main библиотечная функция (sys_stackheap_outer) меняет указатель стека. Что это означает? Может ли библиотечный код пытаться настроить стеки сам? Я вроде даже не давал ему никакой информации о размещении памяти на МК.
Если из стартапа вызываю сразу main, то программа работает, но не инициализируются глобальные переменные. Но если я вызываю __main, то указатель стека изменяется и программа не доходит до main.

Также библиотечный код генерирует программное прерывание (SWI) с кодом 0x123456. Зачем это нужно?


sergeeff
Никто не мешает вам переписать startup модуль под ваши потребности. То что у вас "не инициализируются" глобальные переменные свидетельствует о их неправильном размещении в памяти (сегмент data).
msalov
Для корректного перехода в Main необходим текущий стек правильно настроить. Стартап помимо инициализации указателя на вершину стека инициализирует глобальные и статические переменные. Если вы пишете свой стартап - то должны реализовать необходимый минимум.
imiron13
Цитата(gotty @ Sep 28 2010, 13:23) *
Для корректного перехода в Main необходим текущий стек правильно настроить. Стартап помимо инициализации указателя на вершину стека инициализирует глобальные и статические переменные. Если вы пишете свой стартап - то должны реализовать необходимый минимум.

Ну, на страничке, ссылку на которую я кидал, написано так:
Сначала вызывается начальный код пользователя, который должен:
- инициализировать указатели стеков
- настроить MMU/MPU
- настроить кэш/включить TCM

После должна вызываться __main из стандартной библиотеки Си . __main выполняет следующие действия:
-копирует код (?)
-копирует/распаковывает RW-данные (поэтому нет ничего удивительного, что когда я вызывал сразу main не инициализировались глобальные переменные)
-обнуляет неинициализированные данные

Далее вызывается __rt_entry, которая
- инициализирует библиотечные функции
- вызывает __user_initial_stackheap()
- вызывает $Sub$main()
В основном коде функции __user_initial_stackheap() и $Sub$main() я не переопределял, значит будут вызваны библиотечные. Там же написано, что если используется scatter-файл для линкера, то линкер создаст __user_initial_stackheap(). Scatter-файл я не использую. Что происходит в этом случае?
После этого вызывается main().

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



vallav
Цитата(imiron13 @ Sep 28 2010, 15:27) *
Проблема в том, что библиотечный код изменяет указатель стека и прога рушится. Изменение SP происходит в функции sys_stackheap_outer.


У Вас до исполнения библиотечного кода SP имеет нужное Вам значение?
Чему оно равно и в каком месте присваивается SP?
В Keil для nxp176x сделано так - в стартапе под стек выделяется место в ОЗУ, адрес вершины этого блока ОЗУ и присваивается SP при исполнении
кода, который до main.
А сам код запускается так - делается переход из бутлоадера по адресу, равному значению первого слова во флеше.
В нулевое слово флеша обычно записывается это самое значение для SP, но значение нулевого слова нигде не используется.
imiron13
Цитата(vallav @ Sep 29 2010, 20:38) *
У Вас до исполнения библиотечного кода SP имеет нужное Вам значение?
Чему оно равно и в каком месте присваивается SP?

Да до исполнения библиотечного кода все ок, вот этот кусочек стартапа(стартап самодельный: МК нестандартный) настраивает указатели стека (0x007fff0 - конец ОЗУ)

Код
isrReset
                ldr  r1, =0x007fff0                     ; SP для FIQ
                msr  cpsr_c, #(17 | 0xC0)          ; переход в режи FIQ
                mov  sp, r1
                sub  r1, r1, #1024                     ;FIQ_STACK_SIZE
                msr  cpsr_c, #(18 | 0xC0)         ; переход в режим IRQ
                mov  sp, r1
                sub  r1, r1, #1024                     ;IRQ_STACK_SIZE
                msr  cpsr_c, #(19 | 0xC0)         ; переход в режим Supervisor
                mov  sp, r1                            ; Supervisor SP

Теперь указатели стека имеют верные значения (0007FFF0-FIQ,0007FBF0-IRQ,0007F7F0-SV). Далее работа идет в режиме Supervisor. В конце стартапа:
Код
        ldr     R0, = __main
        BX      R0

Далее выполняется библиотечный код, который изменяет SP. Изменение происходит в функции sys_stackheap_outer (сверял адрес выполняемого кода в отладчике с map-файлом). Ситуация усложняется тем, что не знаю армовский асм, и не могу разобраться, что пытается сделать код, изменяющий SP. Кусочек, изменяющий SP на скрине (до выполнения mov sp,r0 в SP все еще верное значение; вообще-то SP сохраняется в R1, затем в SP возвращается значение из R1, но оно уже затерто). У меня ступор, буду оч благодарен за помощь и советы.
Нажмите для просмотра прикрепленного файла
vallav
Цитата(imiron13 @ Sep 30 2010, 11:43) *
Да до исполнения библиотечного кода все ок, вот этот кусочек стартапа(стартап самодельный: МК нестандартный) настраивает указатели стека (0x007fff0 - конец ОЗУ)

Далее выполняется библиотечный код, который изменяет SP. Изменение происходит в функции sys_stackheap_outer (сверял адрес выполняемого кода в отладчике с map-файлом). Ситуация усложняется тем, что не знаю армовский асм, и не могу разобраться, что пытается сделать код, изменяющий SP. Кусочек, изменяющий SP на скрине (до выполнения mov sp,r0 в SP все еще верное значение; вообще-то SP сохраняется в R1, затем в SP возвращается значение из R1, но оно уже затерто). У меня ступор, буду оч благодарен за помощь и советы.


То, что библиотечная функция при входе сохраняет старое значение стека а при выходе неправильно его восстанавливает -
такое врядли.
Я не знаю, как инициализация стека устроена в Вашем компиляторе.
В разных сделано по разному.
В некоторых - это нужно это делать самому.
В Keil - в вызове __main ( кода инициализации ) перед вызовом main ( самой программы ) стек инициализируется значением
_initial_sp, которое задается в стартапе при выделении блоков памяти.
Выглядит это так:

Stack_Size EQU 0x00000200

AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp

Может у Вас то же самое, но, так как в стартапе Вы этой метке значения не задали, что то идет не так.
У Вас стартап - с нуля самодельный?
А работающего стартапа из примеров ( который можно под свою прогу переделать ) нет?
Student Pupkin
Цитата(imiron13 @ Sep 30 2010, 11:43) *
Теперь указатели стека имеют верные значения (0007FFF0-FIQ,0007FBF0-IRQ,0007F7F0-SV). Далее работа идет в режиме Supervisor. В конце стартапа:
Код
        ldr     R0, = __main
        BX      R0

А для System/User? Там кто SP настраивает? Можете Вы, а может и билиотечная функция (это как пожелаете):
Код
;  Enter User Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_SYS
                IF      :DEF:__MICROLIB

                EXPORT __initial_sp

                ELSE

                MOV     SP, R0
                SUB     SL, SP, #USR_Stack_Size
Кстати и вызов __main надо делать из System или User (в зависимости от того, в каком режиме Вы желаете быть при входе в main() smile.gif ... хотя в сказанном не уверен smile.gif).

Цитата(vallav @ Sep 30 2010, 17:20) *
В Keil - в вызове __main ( кода инициализации ) перед вызовом main ( самой программы ) стек инициализируется значением
_initial_sp, которое задается в стартапе при выделении блоков памяти.
Выглядит это так:

Stack_Size EQU 0x00000200

AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp

Сюдя по всему у топикстартера ARM7/ARM9, а не Cortex (как в LPC17xx)...
vallav
Цитата(Student Pupkin @ Sep 30 2010, 19:58) *
Сюдя по всему у топикстартера ARM7/ARM9, а не Cortex (как в LPC17xx)...


И что?
Все компиляторы Си для ARM7/ARM9 предполагают явную установку стеков в стартапе?
У автора сделана явная и она портится...
Вот и появилось предположение, что это срабатывает неявная.
В Keil для кортекса - что бы Вы не делали с SP в стартапе, в main прога вывалится с SP, равным _initial_sp.
imiron13
Кажется разобрался. Надо было написать функцию __user_initial_stackheap, которая возвращает вершину стека для основного режима, его границу, адрес кучи, ее границу. Заработало. Детали понимаю смутновато. Зачем библиотеке нужно перестраивать стек, и что она пыталась делать, когда я не писал эту функцию.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.