Palm Notes | Recent Changes | Title Index | User Preferences | Random Page | Help
Difference from revision 5 to
the current revision.
major diff minor diff author diff hide diffСтатья
объясняет
идеологию
мультисегментных приложений для PalmOS с использованием GCC.
В
информатике
существует
малоизвестный термин ABI - Application Binary Interface. Этим термином называют набор особенностей компьютерной архитектуры, которые нужно учитывать при создании приложения. ABI может накладываться процессором: направление роста стека, размер элемента данных в стеке, порядок байт в слове итд. Также ABI может накладываться операционной системой. Тогда в ABI входит способ вызова системного API, специфика использования адресного пространства и прочие нюансы. Изменения, которые вносятся в GCC для компиляции под PalmOS, нужны именно для соответствия PalmOS ABI.
Что такое
приложение с
точки зрения
PalmOS? Приложение
- это база
ресурсов.
Четыре
ресурса из
этой базы
используются для исполнения программы.
Это ресурс 'code' #1,
в котором
собственно и
хранится
исполняемый
код, который
запускается
с нулевого
байта
ресурса.
Также из
ресурса 'code' #0
берется
размеры
области
глобальных
данных. Из
ресурса 'pref' #0
берется
размер стека.
И ресурс 'data' #0
используется для инициализации глобальных данных. Все! До всего остального содержимого базы приложения PalmOS дела нет. Подробности можно почитать здесь: http://www.linuxmafia.com/pub/palmos/development/prc-format.html
Такой способ
позволяет
запускать
программы
практически
"на месте",
выделяя
только
память под
стек и
глобальные
переменные.
Какие
ограничения
накладываются на простое односегментное приложение?
* Размер
ресурса 'code' #0
ограничен 64К.
Это
ограничение
было у PalmOS
включая
версию 4 и у
Хотсинка до
версии 5
включительно. Условное ограничение сегмента GCC в 32К лечится заменой скрипта для линкера на text_64k.
*
Ограничение
смещения у
команды
вызова
процедуры в
32К. То есть,
если сегмент
больше 32К, то
функция из
начала не
может
вызвать
функцию в
конце
сегмента. Это
можно обойти
путем
перемещения
вызываемых
функций
"поближе" к
вызываемым
или
созданием
прокси-функций
функций-заглушек
в середине
сегмента.
*
Ограничение
размера
глобальных
данных
программы.
Общий объем
глобальных
данных (в
сумме
инициализированных и неинициализированных) должен укладываться в 64К. Замечу, что константные инициализированные данные помещаются в сегмент кода.
Что
усложнится
при попытке
добавить
новый
сегмент?
Самая
большая
проблема -
межсегментный вызов процедуры. В случае одного сегмента расстояние между процедурами постоянно и код вызова не меняется после компиляции. В случае межсегментного вызова ресурсы могут располагаться в произвольных участках памяти и смещение нужно корректировать.
Замечу, что в
односегментном приложении также происходит коррекция области данных. В нижележащем примере значение переменной pfn будет скорректировано. Это возможно, поскольку сегмент данных находится в динамической памяти. Копировать же все сегменты в динамическую память для коррекции неразумно и расточительно.
<code>
void foo(void){
}
void *pfn = foo;
</code>
Все (оба ;-) )
производители компиляторов для PalmOS предлагают свои поддержки мультисегментности.
Gcc предлагает
следующий
способ:
* Всем
функциям
приписывается
атрибут с
именем
сегмента.
Функции
помещаются в
соответствующие
сегменты.
сегменты
единственного
получаемого
ELF-файла.
* В области
глобальных
переменных
хранятся
адреса всех
сегментов
* При вызове
функции из
другого
семента
происходит
сложение
смещения
функции от
начала
сегмента к
адресу
сегмента из
глобальной
памяти
В чем
ограничения
такого
метода:
*
Использование глобальных данных. Это обозначает, что при вызове программы без глобальных переменных, вызов функций из других сегментов попросту невозможен. При попытке вызвать произойдет обращение к несуществующей области глобалных данных и Fatal Alert неизбежен.
* Этот способ
никак не
расширяет
область
глобальных
данных.
* Проблемы с
доступом к
константным
данным.
Константные
данные могут
оказаться в
другом
сегменте и
тебовать
наличия
глобальных
данных.
* Неявные
функции и
методы
класса. C++
богат на
неявную
генерацию
неявного
кода. Следует
контролировать куда будет помещен код темплейтов и не инлайновых инлайнов.
Подробное
описание
мультисегментной архитектуры GCC здесь: http://prc-tools.sourceforge.net/doc/prc-tools_3.html
Существует
альтернативный способ создания мультисегментных приложений с помощью утилиты multilink. Смотри описание здесь: http://www.djw.org/product/palm/multilink/
Multilink
использует
другую идею:
* Исходные
файлы
компилируются как обычно. Не нужно указывать сегменты в исходном коде
* Утилита
получает на
вход
объектные
файлы и
необязательный список разбиения функций по сегментам.
* Утилита
разбивает
все функции
по сегментам
по списку и
добивает
оставшиеся
до
указанного
размера
сегментов.
* Если
функция foo из
сегмента segA
вызывает bar из
сегмента srgB, то
в segA
добавляется
заглушка для
bar, вызывающая
bar.
* Для
вычисления
адреса bar
используются данные, которые хранятся в feature memory. Тем самым наличие глобальных данных необязательно.
* Полученные
сегменты
добавляются
в программу.
У этого
решения есть
один большой
минус -
невозможен
доступ к
константным
данным из
другого
сегмента.