| Микроконтролери и електроника http://mcu-bg.com/mcu_site/ |
|
| GCC - НЕинициализирани променливи? http://mcu-bg.com/mcu_site/viewtopic.php?f=16&t=6853 |
Страница 1 от 3 |
| Автор: | Цецо [ Сря Май 27, 2009 2:02 pm ] |
| Заглавие: | GCC - НЕинициализирани променливи? |
Как се обявява в GCC статична променлива която не се инициализира от startup кода? |
|
| Автор: | Zdrav [ Сря Май 27, 2009 2:24 pm ] | |||||||||
| Заглавие: | ||||||||||
Аз правя отделна секция в линкер скрипта и после в сорса използвам това:
|
||||||||||
| Автор: | woody [ Сря Май 27, 2009 3:10 pm ] |
| Заглавие: | |
Какво имаш предвид под неинициализирана? Както казва Zdrav, правиш си твоя секция в линкер скрипта и си я слагаш в нея с атрибута за секция. |
|
| Автор: | Цецо [ Сря Май 27, 2009 3:49 pm ] |
| Заглавие: | |
Мда. Ама тоя линкерски език ми е много тегав. Как точно се обяснява на линкера, кои секции трябва да се инициализират и кои не? Иначе става дума точно за променлива обслужваща кучето..... |
|
| Автор: | woody [ Сря Май 27, 2009 4:38 pm ] | ||||||||||||||||||
| Заглавие: | |||||||||||||||||||
Преди да се викне "main()" се изпълнява малко кодец обикновено с име близко до CRT0, идва от "C runtime". Там се прави каквото се прави за съответната платформа/OS. Например се занулява ".bss" секцията и ".data" се копира от ROM ако е била такава постановката. Така че каквато и твоя секция да сложиш, никой няма да ти я прави нищо. Има и друг вариант. Понеже секциите на обектните файлове се събират после в секции на изходния файл (и това се указва от линкер скрипта как точно да става), можеш дори да не правиш специална изходна секция. Достатъчно е да укажеш някаква твоя обектна секция, примерно ".ceco" и после в скрипта да я набуташ в ".text" примерно ако адресното пространсто за код и данни е едно и също и позволява писане (зависи от постановката ти). Или в коя да е друга която отговаря на изискванията ти. Пример:
Линкер-скрипт парчето указва обектната секция ".ceco" да се разположи в изходната ".text". |
|||||||||||||||||||
| Автор: | woody [ Сря Май 27, 2009 4:44 pm ] | |||||||||
| Заглавие: | ||||||||||
А ето и един още по-лесен вариант. Изключи някаква област от RAM-та от линкер скрипта, т.е. да не се ползва. Направи си структура и указател към нея. Инициализирай указателя към парчето директно с абсолютен адрес щом не ти се занимава с линкер скриптове. Воала! Имаш NV променливи (каквато разбирам ти е целта).
|
||||||||||
| Автор: | Цецо [ Сря Май 27, 2009 4:45 pm ] |
| Заглавие: | |
Бе това ми е горе долу ясно. Това което не ми е ясно е как се обяснява коя секция какво да я прави компилатора? Т.е. къде се указва че точно bss трябва да се занули, а точно data да се копира от ROM-a? Гледам линкерския скрипт не виждам подобни "разяснения" в него. .text ми е в FLASH-а, т.е там променливи няма какво да търсят. |
|
| Автор: | miro_atc [ Сря Май 27, 2009 6:34 pm ] | |||||||||
| Заглавие: | ||||||||||
1. Компилаторът генерира обекти - променливи, константи и всякакви други глупости, като за всеки обект се указва секция в обектния файл. По принцип ти с __attribute__ може да кажеш в коя секция искаш дадения обект да бъде разположен, но ако не го направиш ще ти я наблсъка в съответната секция по подразбиране. Поне засега не ми попадала документация относно всички секции по подразбиране. Така че за bss, text и т.н. се ориентирам, но има и разни други дето пък не ги разбирам... 2. Линкерският скрипт описва как от многото обектни файлове и техните секции да се сглоби изходен файл. Така ти на практика определяш разпожението на секциите от обектните файлове в изходния файл (това което казва woody). 3. Линкерът изпълнявайки скрипта разполага всяко нещо на мястото му (евентуално премахва ненужните неща) но в крайна сметка всеки обект си получава конкретни адреси. Включително се изчисляват и константите (етикетите). 4. Обикновено имаш два етикета между които се разполагат променливите в RAM-a. Примерно при мен е:
В случая това са _szero и _ezero. Между тези два адреса линкера ще разположи BSS-те на всички (*) обектни файлове... 5. В стартъп кода имам едно цикълче дето нулира паметта между _szero и _ezero Накратко казано компилатора нищо не указва (освен кое в коя секция на обектния файл се намира). Линкерът (и скрипта) реално разполагат нещата. А стартъп кода е отговорен за нулирането. С други думи по подразбиране нищо в GCC не се инициализира и даже няма изобщо да се линкне. Забрави за С-стандандартите дето ти казват, че static глобална променлива трябва да се нулира - ще се нулира само ако ТИ вкараш такъв линкерски скрипт и стартъп код и го извикаш този код и при това го извикаш навреме (преди да си разрешил прекъсванията). |
||||||||||
| Автор: | woody [ Сря Май 27, 2009 6:51 pm ] |
| Заглавие: | |
Цецо, ела с лапнитоп на бира и ще дигнем мъглата. |
|
| Автор: | Zdrav [ Сря Май 27, 2009 9:02 pm ] | ||||||||||||||||||
| Заглавие: | |||||||||||||||||||
Не че знам повече от woody и miro_atc ама гледам, че има леко разминаване между въпросите и обясненията. По подразбиране всяка глобална променлива която е инициализирана с нещо различно от нула отива в .data секцията. Всички останали глобални променливи отиват в .bss. Стартъп кода е този който решава коя секция да се занули и коя да се копира и коя да не се пипа. miro_atc го е обяснил по-горе механизма. В стартъп кода са видими адресите за начало и край на секциите. И с едно просто цикълче се извършва нулиране или копиране. Като си направиш твоя секция гледай да не съвпадне името и с някоя от стандартните все пак. Щом като са променливи естествено че ще е в RAM. Може да си направиш и отделна изходна секция съдържаща само твоята входна секция.
В стартъп кода просто тази секция няма да се пипа. За да се прави там нещо с нея трябва да си драснеш собственоръчно код в стартъп файла. |
|||||||||||||||||||
| Автор: | Цецо [ Сря Май 27, 2009 9:39 pm ] | |||||||||
| Заглавие: | ||||||||||
Ясно. Утре ще пробвам. А гледам че в моя линкерски скрипт (който съм присвоил), за .data и .bss са дефинирани като:
1. Що за животно е обект от тип COMMON? 2. >ram АТ>rom - що чини тоя "ром" тука? @woody - Абе ти за какъв човек ме имаш? Ще дойда да пием бира и ще седна да с лаптопа да чопля подобни дивотии? Как пък не. Ай сиктир |
||||||||||
| Автор: | woody [ Сря Май 27, 2009 10:03 pm ] |
| Заглавие: | |
Тези готовите линкер скриптове са пълни с какви ли не неща за да угаждат на всички конфигурации и варианти. 1) COMMON са едни стари UNIX разбирания за неинициализираните променливи, че може да ги декларираш във всеки обектен файл и линкерът ги припокрива после. Отсвири го, това е мухъл от някога-бешило, дори ако можеш слагай "-fno-common" че да врещи при дефиниция на повече от едно място. 2) Това най-вероятно са run и load адресите. Run е виртуалния, адресът с който ще се резолвира дадено име. Load е къде физически ще бъде в имиджа. Аз си пиша мои кратки линкер скриптове и CRT0 и си контролирам всичко. Не е трудно и помага за цялостния контрол. Така знам кои променливи са инициализирани, как, кога и т.н. Цената е малко RTFM първия път, после всичко си идва на мястото. Тези концепции са си същите от десетилетки и за щастие всичко е просто и логично. |
|
| Автор: | Цецо [ Вто Юни 16, 2009 12:35 pm ] |
| Заглавие: | |
Следващ въпрос: Как да напъхам константен стринг на специфичен адрес? Трябва ли да му правя отделна секция???? Не мога ли да го направя директно от кода с някакъв атрибут? Нещо от сорта на: const char str[] = "bla-bla" __атрибут тури го ей тука. |
|
| Автор: | Zdrav [ Вто Юни 16, 2009 12:42 pm ] |
| Заглавие: | |
Не, по същия начин със отделна секция се прави. |
|
| Автор: | woody [ Вто Юни 16, 2009 12:52 pm ] |
| Заглавие: | |
С атрибут не може. Нямам под ръка за проба в момента, но пробвай да сложиш в линкер скрипта в правилната секция: str = 0x1234; Другите начини са с отделна секция, като аз лично бих сложил всички такива "фиксирани" данни в една структура. |
|
| Страница 1 от 3 | Часовете са според зоната UTC + 2 часа [ DST ] |
| Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |
|